From b59a90449a6b5682dd5d5bfd1e7461e55a1f8ea5 Mon Sep 17 00:00:00 2001 From: Raj Date: Mon, 27 Sep 2021 16:58:34 +0530 Subject: [PATCH] Update queries to check policy attachment & separation to validate all vs custom iam policies. Fixes #277 Closes #280 (#281) --- cis_v130/section_1.sp | 2 +- cis_v140/section_1.sp | 2 +- foundational_security/iam.sp | 4 +- query/iam/iam_all_policy_no_star_star.sql | 34 +++++++++++++++++ ...iam_custom_policy_no_service_wild_card.sql | 33 ++++++++++++++++ query/iam/iam_custom_policy_no_star_star.sql | 38 +++++++++++-------- 6 files changed, 93 insertions(+), 20 deletions(-) create mode 100644 query/iam/iam_all_policy_no_star_star.sql create mode 100644 query/iam/iam_custom_policy_no_service_wild_card.sql diff --git a/cis_v130/section_1.sp b/cis_v130/section_1.sp index 07964187..28eba5bc 100644 --- a/cis_v130/section_1.sp +++ b/cis_v130/section_1.sp @@ -247,7 +247,7 @@ control "cis_v130_1_15" { control "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." - sql = query.iam_policy_no_star_star.sql + sql = query.iam_all_policy_no_star_star.sql documentation = file("./cis_v130/docs/cis_v130_1_16.md") tags = merge(local.cis_v130_1_common_tags, { diff --git a/cis_v140/section_1.sp b/cis_v140/section_1.sp index 1c9ea72c..218b8d59 100644 --- a/cis_v140/section_1.sp +++ b/cis_v140/section_1.sp @@ -246,7 +246,7 @@ control "cis_v140_1_15" { control "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." - sql = query.iam_policy_no_star_star.sql + sql = query.iam_all_policy_no_star_star.sql documentation = file("./cis_v140/docs/cis_v140_1_16.md") tags = merge(local.cis_v140_1_common_tags, { diff --git a/foundational_security/iam.sp b/foundational_security/iam.sp index 02dc469b..91ee8a2e 100644 --- a/foundational_security/iam.sp +++ b/foundational_security/iam.sp @@ -25,7 +25,7 @@ control "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." severity = "high" - sql = query.iam_policy_no_star_star.sql + sql = query.iam_custom_policy_no_star_star.sql documentation = file("./foundational_security/docs/foundational_security_iam_1.md") tags = merge(local.foundational_security_iam_common_tags, { @@ -129,7 +129,7 @@ control "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:*'." severity = "low" - sql = query.iam_custom_policy_no_star_star.sql + sql = query.iam_custom_policy_no_service_wild_card.sql documentation = file("./foundational_security/docs/foundational_security_iam_21.md") tags = merge(local.foundational_security_iam_common_tags, { diff --git a/query/iam/iam_all_policy_no_star_star.sql b/query/iam/iam_all_policy_no_star_star.sql new file mode 100644 index 00000000..35a397de --- /dev/null +++ b/query/iam/iam_all_policy_no_star_star.sql @@ -0,0 +1,34 @@ +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 + s ->> 'Effect' = 'Allow' + and resource = '*' + and ( + (action = '*' + or action = '*:*' + ) + ) + and attachment_count !=0 + group by arn + ) +select + -- Required Columns + p.arn as resource, + 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, + -- Additional Dimensions + p.account_id +from + aws_iam_policy as p + left join star_access_policies as s on p.arn = s.arn; \ No newline at end of file diff --git a/query/iam/iam_custom_policy_no_service_wild_card.sql b/query/iam/iam_custom_policy_no_service_wild_card.sql new file mode 100644 index 00000000..0dfbd958 --- /dev/null +++ b/query/iam/iam_custom_policy_no_service_wild_card.sql @@ -0,0 +1,33 @@ +with wildcard_action_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 + is_aws_managed = 'false' + and s ->> 'Effect' = 'Allow' + and resource = '*' + and action like '%:*' + group by + arn +) +select + -- Required Columns + a.arn as resource, + case + when b.arn is null then 'ok' + else 'alarm' + end status, + a.name || ' contains ' || coalesce(b.statements_num,0) || + ' statements that allow action "Service:*" on resource "*".' as reason, + -- Additional Dimensions + a.account_id +from + aws_iam_policy as a + left join wildcard_action_policies as b on a.arn = b.arn +where + a.arn not like 'arn:aws:iam::aws:policy%'; diff --git a/query/iam/iam_custom_policy_no_star_star.sql b/query/iam/iam_custom_policy_no_star_star.sql index 5f715d2f..41fb42c1 100644 --- a/query/iam/iam_custom_policy_no_star_star.sql +++ b/query/iam/iam_custom_policy_no_star_star.sql @@ -1,33 +1,39 @@ -with wildcard_action_policies as ( +-- This query checks the customer managed policies having * access and attached to IAM resource(s) +with star_access_policies as ( select arn, - count(*) as statements_num + 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 - is_aws_managed = 'false' - and s ->> 'Effect' = 'Allow' + s ->> 'Effect' = 'Allow' and resource = '*' - and action like '%:*' - group by - arn -) + and ( + (action = '*' + or action = '*:*' + ) + ) + -- Checking attachment + and attachment_count !=0 + group by arn + ) select -- Required Columns - a.arn as resource, + p.arn as resource, case - when b.arn is null then 'ok' + when s.arn is null then 'ok' else 'alarm' end status, - a.name || ' contains ' || coalesce(b.statements_num,0) || - ' statements that allow action "Service:*" on resource "*".' as reason, + p.name || ' contains ' || coalesce(s.num_bad_statements,0) || + ' statements that allow action "*" on resource "*".' as reason, -- Additional Dimensions - a.account_id + p.account_id from - aws_iam_policy as a - left join wildcard_action_policies as b on a.arn = b.arn + aws_iam_policy as p + left join star_access_policies as s on p.arn = s.arn where - a.arn not like 'arn:aws:iam::aws:policy%' + -- Filter only customer managed policies + p.arn not like 'arn:aws:iam::aws:policy%'; \ No newline at end of file