{"id":1173,"date":"2024-03-29T17:09:00","date_gmt":"2024-03-29T17:09:00","guid":{"rendered":"https:\/\/badbadger.tech\/?p=1173"},"modified":"2025-02-24T23:19:34","modified_gmt":"2025-02-24T23:19:34","slug":"iam-shadow-permissions-intro","status":"publish","type":"post","link":"https:\/\/badbadger.tech\/?p=1173","title":{"rendered":"What Lurks in the Shadows of IAM? The Hidden Risk  of Shadow Permissions"},"content":{"rendered":"\n<p>IAM policies are like layered security badges\u2014one might deny you entry, but you&#8217;re in if another gives you an all-access pass. This is AWS IAM Policy Shadowing.<\/p>\n\n\n\n<p>If you&#8217;re managing AWS IAM policies, you probably feel pretty confident about your security controls. But what if I told you there\u2019s a hidden risk that could be giving users more access than you intended\u2014without you even realizing it? This journey is as much about me learning as it is about sharing what I find. Let&#8217;s explore <strong>IAM Policy Shadowing<\/strong> together.<\/p>\n\n\n\n<p>AWS IAM is powerful but complex. With policies layered across users, roles, groups, permission boundaries, service control policies (SCPs), and resource-based policies, it\u2019s easy for one policy to override another in unexpected ways. I\u2019ve started digging into this: when an explicitly denied action still gets allowed or permissions don\u2019t behave the way you expect.<\/p>\n\n\n\n<p>Let\u2019s uncover how <strong>IAM Policy Shadowing<\/strong> happens, why it\u2019s a security risk, and what we can do about it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is AWS IAM Policy Shadowing?<\/strong><\/h2>\n\n\n\n<p>IAM Policy Shadowing occurs when one policy unintentionally overrides another, creating excessive permissions or ineffective restrictions. This usually happens when multiple policies interact in ways that aren&#8217;t immediately obvious. Here are some examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <strong>deny policy<\/strong> in an SCP gets overridden by an allow statement in an IAM policy attached to a user or role.<\/li>\n\n\n\n<li>A <strong>permission boundary<\/strong> is set to restrict an action, but an attached managed policy grants broader access.<\/li>\n\n\n\n<li>A <strong>resource-based policy<\/strong> allows access that an identity-based policy should deny.<\/li>\n\n\n\n<li><strong>AWS-managed policies<\/strong> grant excessive permissions that override custom least-privilege policies.<\/li>\n<\/ul>\n\n\n\n<p>At first glance, your IAM policies might look solid, but shadowing can creep in silently. That\u2019s why I\u2019m making this my focus\u2014if it&#8217;s tripping me up, I&#8217;m sure others are facing it too.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Why is This a Problem?<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>1. Unintended Privilege Escalation<\/strong><\/h4>\n\n\n\n<p>Policy shadowing can lead to users or services having permissions beyond what was intended. This could allow a developer to delete critical resources, an attacker to escalate privileges, or a misconfigured automation script to make unintended changes.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>2. Compliance and Audit Failures<\/strong><\/h4>\n\n\n\n<p>Security frameworks like <strong>ISO 27001, SOC2, and NIST<\/strong> require strict access control. Shadowed policies can make it seem like permissions are restricted when, in reality, a different policy might be granting unexpected access.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>3. Difficult to Detect and Troubleshoot<\/strong><\/h4>\n\n\n\n<p>AWS IAM policies follow a specific <strong>policy evaluation logic<\/strong> (which I\u2019ll dive into in future posts). Shadowing issues aren\u2019t always apparent unless you analyze how multiple policies interact.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Example Scenario: When Policies Clash<\/strong><\/h3>\n\n\n\n<p>Let\u2019s say you apply an SCP at the organizational unit (OU) level to prevent users from deleting S3 buckets:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{<br>  \"Effect\": \"Deny\",<br>  \"Action\": \"s3:DeleteBucket\",<br>  \"Resource\": \"*\"<br>}<\/pre>\n\n\n\n<p>However, an inline IAM policy attached to a developer role includes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"Effect\": \"Allow\",\n  \"Action\": \"s3:*\",\n  \"Resource\": \"*\"\n}<\/code><\/pre>\n\n\n\n<p>If the SCP should override all IAM policies, then the delete action should be blocked, right? Not necessarily! <strong>Another attached policy could override the deny<\/strong>, allowing deletion depending on where the policies are applied. Understanding the interaction between IAM policies, SCPs, permission boundaries, and resource-based policies is crucial.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What\u2019s Next?<\/strong><\/h3>\n\n\n\n<p>This is just the beginning. Over the next few months, I\u2019ll be:<\/p>\n\n\n\n<p>\u2705 <strong>Exploring how to detect AWS IAM Policy Shadowing using native tools<\/strong> (IAM Access Analyzer, CloudTrail, AWS Config, and third-party tools).<br>\u2705 <strong>Breaking down AWS IAM Policy Shadowing evaluation logic<\/strong> to understand why shadowing happens.<br>\u2705 <strong>Showing hands-on examples of fixing policy conflicts<\/strong> with real-world scenarios.<br>\u2705 <strong>Discussing compliance risks and how to document IAM controls properly.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Join Me on This Learning Journey<\/strong><\/h3>\n\n\n\n<p>If you\u2019ve encountered IAM policies behaving in unexpected ways, let\u2019s talk! Share your experiences, questions, or horror stories\u2014I\u2019d love to hear them. I\u2019ll be posting regularly, and I\u2019ll incorporate your feedback and challenges into upcoming posts.<\/p>\n\n\n\n<p>Stay tuned for next month\u2019s deep dive: <strong>How to Detect IAM Policy Shadowing in AWS Using Built-in Tools.<\/strong><\/p>\n\n\n\n<p>Let\u2019s demystify IAM policies together.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Where to Learn More<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>AWS Documentation<\/strong>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/reference_policies_evaluation-logic.html\">IAM Policy Evaluation Logic<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/access-analyzer-policy-checks.html\">IAM Access Analyzer<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Tools for Policy Analysis<\/strong>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/aws.amazon.com\/blogs\/security\/how-to-use-iam-access-analyzer-to-generate-least-privilege-iam-policies\/\">AWS IAM Access Analyzer<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/duo-labs\/parliament\">Parliament &#8211; Open Source AWS IAM Linter<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/salesforce\/policy_sentry\">Policy Sentry &#8211; IAM Least Privilege Generator<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Blog Posts and Deep Dives<\/strong>\n<ul class=\"wp-block-list\">\n<li>AWS Security Blog \u2013 <a href=\"https:\/\/aws.amazon.com\/blogs\/security\/tag\/iam\/\">Best Practices for AWS IAM Policies<\/a><\/li>\n\n\n\n<li>Rhino Security Labs \u2013 <a>AWS IAM Security Flaws<\/a><\/li>\n\n\n\n<li>NCC Group Research \u2013 <a>AWS IAM Risks and Analysis<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>IAM policies are like layered security badges\u2014one might deny you entry, but you&#8217;re in if another gives you an all-access pass. This is AWS IAM Policy Shadowing. If you&#8217;re managing AWS IAM policies, you probably feel pretty confident about your security controls. But what if I told you there\u2019s a hidden risk that could be&#8230;<\/p>\n","protected":false},"author":2,"featured_media":1178,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[12,17],"tags":[53,41,55,46,64,68,43,52,58,70,62,57,49,48,50,45,59,60,54,67,42,69,51,56,66,47,65,61,63,44],"class_list":["post-1173","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-techniques","category-tools","tag-aws-compliance","tag-aws-iam","tag-aws-iam-access-analyzer","tag-aws-iam-best-practices","tag-aws-iam-best-practices-2024","tag-aws-iam-compliance-risks","tag-aws-iam-policy","tag-aws-iam-policy-conflicts","tag-aws-iam-policy-evaluation","tag-aws-iam-policy-tools","tag-aws-iam-policy-troubleshooting","tag-aws-iam-role-configuration","tag-aws-iam-troubleshooting","tag-aws-identity-and-access-management","tag-aws-least-privilege","tag-aws-permissions","tag-aws-policy-simulator","tag-aws-privilege-escalation","tag-aws-role-based-access-control","tag-aws-scps-vs-iam-policies","tag-aws-security","tag-aws-security-audit","tag-aws-security-best-practices","tag-aws-security-hub","tag-aws-security-misconfigurations","tag-cloud-security","tag-detecting-excessive-aws-permissions","tag-fixing-aws-iam-policies","tag-how-to-secure-aws-iam","tag-iam-policy-shadowing"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/posts\/1173","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/badbadger.tech\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1173"}],"version-history":[{"count":2,"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/posts\/1173\/revisions"}],"predecessor-version":[{"id":1176,"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/posts\/1173\/revisions\/1176"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/badbadger.tech\/index.php?rest_route=\/wp\/v2\/media\/1178"}],"wp:attachment":[{"href":"https:\/\/badbadger.tech\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1173"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/badbadger.tech\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1173"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/badbadger.tech\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1173"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}