<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GCP IAM Archives - Linuxcent</title>
	<atom:link href="https://linuxcent.com/tag/gcp-iam/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxcent.com/tag/gcp-iam/</link>
	<description>Infrastructure security, from the kernel up.</description>
	<lastBuildDate>Mon, 06 Jul 2026 05:16:57 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxcent.com/wp-content/uploads/2026/04/favicon-512x512-1-150x150.png</url>
	<title>GCP IAM Archives - Linuxcent</title>
	<link>https://linuxcent.com/tag/gcp-iam/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">211632295</site>	<item>
		<title>New Cloud Service IAM Permissions: A Checklist Before You Grant Access</title>
		<link>https://linuxcent.com/new-service-iam-permissions-checklist/</link>
					<comments>https://linuxcent.com/new-service-iam-permissions-checklist/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Mon, 06 Jul 2026 05:16:54 +0000</pubDate>
				<category><![CDATA[Cloud IAM]]></category>
		<category><![CDATA[Access Analyzer]]></category>
		<category><![CDATA[AWS IAM]]></category>
		<category><![CDATA[Azure RBAC]]></category>
		<category><![CDATA[Cloud Security]]></category>
		<category><![CDATA[GCP IAM]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[Least Privilege]]></category>
		<guid isPermaLink="false">https://linuxcent.com/new-service-iam-permissions-checklist/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 7</span> <span class="rt-label rt-postfix">minutes</span></span>New cloud service IAM permissions ship on GA day — this five-step AWS, GCP, and Azure checklist scopes them correctly before you grant broad access.</p>
<p>The post <a href="https://linuxcent.com/new-service-iam-permissions-checklist/">New Cloud Service IAM Permissions: A Checklist Before You Grant Access</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 7</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<p><a href="/zero-trust-iam/">← EP12: Zero Trust Access in the Cloud</a>  ·  <strong>EP13: New-Service IAM Checklist</strong>  ·  <a href="/cloud-iam-series/">All Cloud IAM Episodes →</a></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>New cloud service IAM permissions ship on GA day — often before your Terraform provider, internal IaC modules, or team wiki catch up</li>
<li>The fast path is <code class="" data-line="">service:*</code> on <code class="" data-line="">Resource: *</code> — the tempting unblock, and also how wildcard debt starts (see <a href="/iam-least-privilege-audit/">EP09&#8217;s least-privilege audit</a>)</li>
<li>Five-step checklist: find the exact actions, scope the resource, dry-run before granting, attach a guardrail, and put a 30-day review on the calendar</li>
<li>AWS has no single CLI call that lists &#8220;every action for a service&#8221; — use the Service Authorization Reference plus IAM Access Analyzer&#8217;s policy generation from real CloudTrail activity</li>
<li>GCP&#8217;s <code class="" data-line="">gcloud iam list-testable-permissions</code> returns the exact permissions grantable on a specific resource — scoped to what that resource type actually supports</li>
<li>Azure&#8217;s <code class="" data-line="">az provider operation show --namespace Microsoft.&lt;Service&gt;</code> lists every operation a resource provider exposes, before you write a single role assignment</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">  NEW CLOUD SERVICE SHIPS — THE FIRST GRANT DECIDES THE NEXT YEAR

  Provider ships GA
         │
         ▼
  Team requests access ──────► Tempting shortcut: &quot;service:*&quot; on &quot;*&quot;
         │                      (unblocks today, becomes next year&#039;s
         │                       wildcard-debt line item in EP09&#039;s audit)
         ▼
  STEP 1 — Find the exact actions the task needs
         │   (Service Authorization Reference · list-testable-permissions ·
         │    provider operation show)
         ▼
  STEP 2 — Scope the resource, not the account
         │   (ARN pattern / resource URI / resource group — never &quot;*&quot;)
         ▼
  STEP 3 — Dry-run before granting
         │   (simulate-principal-policy · policy-troubleshoot iam · what-if)
         ▼
  STEP 4 — Attach a guardrail, not just a grant
         │   (permission boundary / SCP · Org Policy · Azure Policy)
         ▼
  STEP 5 — Put a 30-day review on the calendar
         │   (provisional access, not permanent — EP09&#039;s audit is the
         │    backstop for whatever step 5 misses)
         ▼
  Access granted: scoped, guarded, and time-boxed
</code></pre>
<hr />
<h2 id="introduction">Introduction</h2>
<p>New cloud service IAM permissions land the same day a provider ships something new — usually before your Terraform provider, your internal enablement docs, or anyone&#8217;s muscle memory has caught up. A team wants to use the new service today, and the fastest way to unblock them is a wildcard: <code class="" data-line="">service:*</code> on <code class="" data-line="">Resource: *</code>. It works immediately. It also never gets revisited.</p>
<p>I&#8217;ve seen this pattern enough times across AWS, GCP, and Azure environments to stop treating it as a one-off mistake and start treating it as a predictable failure mode. Every cloud provider ships new services and new API actions on existing services continuously — thousands of changes a year across the big three. IAM has to keep up with all of it, and nobody&#8217;s tooling updates same-day. The gap between &#8220;the service exists&#8221; and &#8220;the least-privilege policy for it exists&#8221; is where every wildcard grant in your account was born.</p>
<p>This episode is the checklist I use to close that gap before it becomes <a href="/iam-least-privilege-audit/">EP09&#8217;s least-privilege audit</a> problem six months later.</p>
<hr />
<h2 id="why-this-keeps-happening">Why This Keeps Happening</h2>
<p>Cloud providers version their IAM action sets independently of their service launches. A service can go GA with its full action list, then add new actions for a feature shipped three months later — with no changelog most teams are subscribed to. Preview and beta services are worse: action names occasionally change between preview and GA, which means a policy scoped correctly during the beta can silently stop matching after the rename.</p>
<p>None of this is a documentation failure you can fix by reading more carefully. It&#8217;s a structural lag between provider release velocity and your policy review cycle. The fix isn&#8217;t reading faster — it&#8217;s having a checklist that runs the same way every time a new service shows up in a support ticket.</p>
<hr />
<h2 id="step-1-find-the-exact-actions-the-task-needs">Step 1: Find the Exact Actions the Task Needs</h2>
<h3 id="aws">AWS</h3>
<p>AWS doesn&#8217;t expose a single CLI call that lists &#8220;every action for this service.&#8221; The two real sources:</p>
<ol>
<li>The <a href="https://docs.aws.amazon.com/service-authorization/latest/reference/">Service Authorization Reference</a> — the canonical, per-service action/resource/condition-key list. Not a CLI, but the ground truth.</li>
<li>IAM Access Analyzer&#8217;s policy generation — build a least-privilege policy from what a role <em>actually called</em>, not from the full service action list:</li>
</ol>
<pre><code class="" data-line=""># Let a trial role use the new service for a short period first, then generate
# a policy scoped to only the actions that were actually invoked
aws accessanalyzer start-policy-generation \
  --policy-generation-details principalArn=arn:aws:iam::123456789012:role/new-service-trial-role \
  --cloud-trail-details &#039;{
    &quot;trails&quot;: [{&quot;cloudTrailArn&quot;: &quot;arn:aws:cloudtrail:us-east-1:123456789012:trail/management-trail&quot;, &quot;allRegions&quot;: true}],
    &quot;accessRole&quot;: &quot;arn:aws:iam::123456789012:role/AccessAnalyzerMonitorRole&quot;
  }&#039;

# Poll for the generated policy once the job completes
aws accessanalyzer get-generated-policy --job-id &lt;JOB_ID&gt;
</code></pre>
<blockquote>
<p><strong>For operators:</strong> this generates a policy from <em>observed</em> API calls, not theoretical need. Run the trial role for long enough to exercise every code path the team actually uses — a policy generated from five minutes of testing will be too narrow for production.</p>
</blockquote>
<h3 id="gcp">GCP</h3>
<pre><code class="" data-line=""># Returns the exact permissions that CAN be granted on this specific resource —
# scoped to what that resource type supports, not the whole service
gcloud iam list-testable-permissions \
  //aiplatform.googleapis.com/projects/my-project/locations/us-central1
</code></pre>
<p>Reading the output: each returned permission is one your team might plausibly need — GCP won&#8217;t list permissions that don&#8217;t apply to this resource type. Cross-reference against the task at hand and grant only the subset actually required.</p>
<h3 id="azure">Azure</h3>
<pre><code class="" data-line=""># Lists every operation (permission) a resource provider namespace exposes
az provider operation show \
  --namespace Microsoft.CognitiveServices \
  --query &quot;[].{Operation:name, Description:display.description}&quot; \
  -o table
</code></pre>
<p>This is the full menu for the namespace — most tasks need a handful of these operations, not all of them. Use it to find the exact operation string for a custom role definition rather than reaching for a built-in <code class="" data-line="">Contributor</code>-level role.</p>
<hr />
<h2 id="step-2-scope-the-resource-not-the-account">Step 2: Scope the Resource, Not the Account</h2>
<p>Finding the right action is half the job. The other half is refusing <code class="" data-line="">&quot;Resource&quot;: &quot;*&quot;</code>.</p>
<pre><code class="" data-line="">// Bad — every foundation model, in every region, forever
{
  &quot;Effect&quot;: &quot;Allow&quot;,
  &quot;Action&quot;: &quot;bedrock:*&quot;,
  &quot;Resource&quot;: &quot;*&quot;
}

// Better — scoped to the specific model family the team asked for
{
  &quot;Effect&quot;: &quot;Allow&quot;,
  &quot;Action&quot;: [&quot;bedrock:InvokeModel&quot;],
  &quot;Resource&quot;: &quot;arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude*&quot;
}
</code></pre>
<p>The same discipline applies in GCP (bind the role to the specific project or resource, not the organization) and Azure (scope the role assignment to the resource group, not the subscription). A new service is the easiest moment to get this right — there&#8217;s no existing wildcard grant to &#8220;just extend.&#8221;</p>
<hr />
<h2 id="step-3-dry-run-before-you-grant">Step 3: Dry-Run Before You Grant</h2>
<p>Test the policy against the real action before it&#8217;s live.</p>
<pre><code class="" data-line=""># AWS: simulate whether a principal&#039;s policy allows a specific action on a specific resource
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/new-service-role \
  --action-names bedrock:InvokeModel \
  --resource-arns arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2
</code></pre>
<pre><code class="" data-line=""># GCP: Policy Troubleshooter — does this principal have this permission on this resource, and why (or why not)?
gcloud policy-troubleshoot iam \
  //aiplatform.googleapis.com/projects/my-project/locations/us-central1 \
  --principal-email=svc-new-service@my-project.iam.gserviceaccount.com \
  --permission=aiplatform.endpoints.predict
</code></pre>
<pre><code class="" data-line=""># Azure: preview what an IaC deployment (including role assignments) will change before applying it
az deployment group what-if \
  --resource-group rg-new-service \
  --template-file role-assignment.bicep
</code></pre>
<p>None of these grant access. All three tell you, before the grant is live, whether the policy you wrote actually does what you think it does.</p>
<hr />
<h2 id="step-4-attach-a-guardrail-not-just-a-grant">Step 4: Attach a Guardrail, Not Just a Grant</h2>
<p>A grant without a guardrail is one typo away from being an account-wide wildcard. Pair every new-service grant with a boundary that survives the next person copy-pasting the policy:</p>
<ul>
<li><strong>AWS</strong> — a permission boundary on the role, or an SCP restricting the new service to specific OUs until it&#8217;s been reviewed</li>
<li><strong>GCP</strong> — an Org Policy constraint limiting resource locations or restricting which services can be enabled in the first place</li>
<li><strong>Azure</strong> — an Azure Policy assignment enforcing an allowed-services list at the subscription or management group level</li>
</ul>
<p>The guardrail is what keeps &#8220;we scoped it correctly on day one&#8221; true after the policy gets copied into three other roles by someone who wasn&#8217;t in this conversation.</p>
<hr />
<h2 id="step-5-put-a-30-day-review-on-the-calendar">Step 5: Put a 30-Day Review on the Calendar</h2>
<p>Treat every new-service grant as provisional, not permanent. A calendar reminder — not a ticket that can sit in a backlog — to check actual usage against granted permissions 30 days out.</p>
<p>This is the same discipline <a href="/iam-least-privilege-audit/">EP09&#8217;s least-privilege audit</a> runs at the account level, applied at the moment of grant instead of six months later. Step 5 is what catches the case where the team&#8217;s actual usage turned out narrower than the trial period suggested — or wider, because the trial period didn&#8217;t exercise every path.</p>
<hr />
<h2 id="production-gotchas">Production Gotchas</h2>
<table>
<thead>
<tr>
<th>Mistake</th>
<th>Impact</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td>Granting console-wide access &#8220;temporarily&#8221; while waiting for Terraform provider support</td>
<td>Temporary access outlives the wait — nobody revokes it once the provider resource ships</td>
<td>Time-box the console grant explicitly; automate its removal, don&#8217;t rely on memory</td>
</tr>
<tr>
<td>Scoping a policy to a preview/beta action name</td>
<td>Silent breakage (or worse, silent continued access via an old wildcard) when the action renames at GA</td>
<td>Re-verify the action name against the Service Authorization Reference at GA, not just at preview</td>
</tr>
<tr>
<td>Assuming a new service reuses an existing condition key</td>
<td>Policy conditions that &#8220;should&#8221; restrict access silently don&#8217;t apply, because the new service doesn&#8217;t support that key</td>
<td>Check the service&#8217;s supported condition keys before reusing an existing policy pattern</td>
</tr>
<tr>
<td>Trial period too short for Access Analyzer&#8217;s policy generation</td>
<td>Generated policy is too narrow; production breaks on day one under real load</td>
<td>Run the trial long enough to exercise every code path, including error and retry paths</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<table>
<thead>
<tr>
<th>Task</th>
<th>AWS</th>
<th>GCP</th>
<th>Azure</th>
</tr>
</thead>
<tbody>
<tr>
<td>Discover exact actions</td>
<td>Service Authorization Reference + <code class="" data-line="">accessanalyzer start-policy-generation</code></td>
<td><code class="" data-line="">gcloud iam list-testable-permissions &lt;resource&gt;</code></td>
<td><code class="" data-line="">az provider operation show --namespace &lt;Provider&gt;</code></td>
</tr>
<tr>
<td>Dry-run a grant</td>
<td><code class="" data-line="">aws iam simulate-principal-policy</code></td>
<td><code class="" data-line="">gcloud policy-troubleshoot iam</code></td>
<td><code class="" data-line="">az deployment group what-if</code></td>
</tr>
<tr>
<td>Guardrail</td>
<td>Permission boundary / SCP</td>
<td>Org Policy constraint</td>
<td>Azure Policy assignment</td>
</tr>
<tr>
<td>Recurring check</td>
<td><code class="" data-line="">aws accessanalyzer</code> unused-access findings</td>
<td>IAM Recommender</td>
<td>Access Reviews</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="framework-alignment">Framework Alignment</h2>
<table>
<thead>
<tr>
<th>Framework</th>
<th>Control / ID</th>
<th>Mapping</th>
</tr>
</thead>
<tbody>
<tr>
<td>CISSP</td>
<td>Domain 5 — IAM</td>
<td>Least privilege enforced at initial provisioning, not discovered later through audit</td>
</tr>
<tr>
<td>CISSP</td>
<td>Domain 1 — Security &amp; Risk Management</td>
<td>Provisional access as a risk-acceptance decision with an explicit review date</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.15 Access control</td>
<td>Access rights defined and scoped to business need at the point of grant</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.18 Access rights</td>
<td>Review of access rights — extended here to newly granted permissions, not just standing ones</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.1</td>
<td>Logical access controls restrict access to authorized users and processes from first grant</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.3</td>
<td>Access is modified or revoked based on a defined review cadence</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>New cloud service IAM permissions ship on the provider&#8217;s schedule, not yours — the checklist has to run the same way every time, not only when someone remembers</li>
<li>The fast path (<code class="" data-line="">service:*</code> on <code class="" data-line="">*</code>) is also the path to next year&#8217;s wildcard-debt finding — scope it once, at the point of grant, instead of unwinding it later</li>
<li>AWS, GCP, and Azure each expose a different tool for discovering exact actions — none of them is &#8220;read the whole service&#8217;s docs and guess&#8221;</li>
<li>A grant without a guardrail (permission boundary, SCP, Org Policy, Azure Policy) is one copy-paste away from becoming account-wide</li>
<li>Provisional access needs an expiration built in from day one — a 30-day calendar review, not a hope that someone runs the audit eventually</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>This series doesn&#8217;t have a fixed episode count anymore — new cloud service IAM permissions are a continuous stream across AWS, GCP, and Azure, and this series continues covering them as they matter operationally, not on a fixed syllabus.</p>
<p>Get the next Cloud IAM episode in your inbox → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&amp;linkname=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fnew-service-iam-permissions-checklist%2F&#038;title=New%20Cloud%20Service%20IAM%20Permissions%3A%20A%20Checklist%20Before%20You%20Grant%20Access" data-a2a-url="https://linuxcent.com/new-service-iam-permissions-checklist/" data-a2a-title="New Cloud Service IAM Permissions: A Checklist Before You Grant Access"></a></p><p>The post <a href="https://linuxcent.com/new-service-iam-permissions-checklist/">New Cloud Service IAM Permissions: A Checklist Before You Grant Access</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/new-service-iam-permissions-checklist/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2176</post-id>	</item>
		<item>
		<title>GCP IAM Policy Inheritance: How the Resource Hierarchy Controls Access</title>
		<link>https://linuxcent.com/gcp-iam-deep-dive/</link>
					<comments>https://linuxcent.com/gcp-iam-deep-dive/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 15 Apr 2026 18:06:02 +0000</pubDate>
				<category><![CDATA[Cloud IAM]]></category>
		<category><![CDATA[Cloud Security]]></category>
		<category><![CDATA[GCP IAM]]></category>
		<category><![CDATA[GCP Security]]></category>
		<category><![CDATA[Google Cloud IAM]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[Service Accounts]]></category>
		<category><![CDATA[Workload Identity]]></category>
		<guid isPermaLink="false">https://linuxcent.com/gcp-iam-deep-dive/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 11</span> <span class="rt-label rt-postfix">minutes</span></span>GCP IAM explained: resource hierarchy, predefined vs custom roles, service accounts, workload identity federation, and why the inheritance model changes access control.</p>
<p>The post <a href="https://linuxcent.com/gcp-iam-deep-dive/">GCP IAM Policy Inheritance: How the Resource Hierarchy Controls Access</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 11</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><a href="/what-is-cloud-iam/">What Is Cloud IAM</a> → <a href="/authentication-vs-authorization-iam/">Authentication vs Authorization</a> → <a href="/iam-roles-policies-permissions-explained/">IAM Roles vs Policies</a> → <a href="/aws-iam-deep-dive/">AWS IAM Deep Dive</a> → <strong>GCP Resource Hierarchy IAM</strong> → <a href="/azure-rbac-entra-id-guide/">Azure RBAC Scopes</a></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>GCP IAM bindings inherit downward — a binding at Organization or Folder level applies to every project and resource beneath it</li>
<li>Basic roles (<code class="" data-line="">viewer</code>/<code class="" data-line="">editor</code>/<code class="" data-line="">owner</code>) are legacy constructs; use predefined or custom roles in production</li>
<li>Service account keys are a long-lived credential antipattern — use ADC, impersonation, or Workload Identity Federation instead</li>
<li><code class="" data-line="">allAuthenticatedUsers</code> bindings expose resources to any of 3 billion Google accounts — audit for these in every environment</li>
<li><code class="" data-line="">iam.serviceAccounts.actAs</code> is the GCP equivalent of AWS <code class="" data-line="">iam:PassRole</code> — a direct privilege escalation vector</li>
<li>Conditional bindings with time-bound expiry eliminate &#8220;I&#8217;ll remember to remove this&#8221; as an operational pattern</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">                GCP IAM Inheritance Model
─────────────────────────────────────────────────────────
Organization (company.com)
│
├─ IAM binding at Org level ──────────────────┐
│                                             │ inherits down
├── Folder: Production                        ▼
│   │                                 ALL nodes below
│   ├── Folder: Shared-Services
│   │       └── Project: infra-core
│   │               ├── GCS: config-bucket  ← affected
│   │               └── Secret Manager      ← affected
│   │
│   └── Project: prod-web-app
│           ├── GCS: prod-assets             ← affected
│           ├── Cloud SQL: prod-db           ← affected
│           └── BigQuery: analytics          ← affected
│
└── Folder: Development                      ← NOT affected by
        └── Project: dev-app                    Production binding
</code></pre>
<p>GCP resource hierarchy IAM inheritance is the mechanism that makes a single binding cascade through an entire estate. It&#8217;s also the reason high-level bindings carry far more blast radius than they appear to.</p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>GCP resource hierarchy IAM operates on one rule: bindings propagate downward. Grant access at the Organization level and it applies to every Folder, every Project, and every resource in your GCP estate. Grant it at a Folder and it applies to every Project below. This is by design — and it&#8217;s the reason IAM misconfigurations in GCP can have a blast radius that teams migrating from AWS don&#8217;t anticipate.</p>
<p>I once inherited a GCP environment where the previous team had taken what they thought was a shortcut. They had a folder called <code class="" data-line="">Production</code> with twelve projects in it. Rather than grant developers access to each project individually, they bound <code class="" data-line="">roles/editor</code> at the folder level. One binding, twelve projects, all covered. Fast.</p>
<p>When I audited what <code class="" data-line="">roles/editor</code> on that folder actually meant, I found it gave every developer in that binding write access to Cloud SQL databases they&#8217;d never heard of, BigQuery datasets from other teams, Pub/Sub topics in shared services, and Cloud Storage buckets that held data exports. Not because anyone intended that. Because permissions in GCP flow downward through the hierarchy, and a broad role at a high level means a broad role everywhere below it.</p>
<p>The developer who made that binding understood &#8220;Editor means edit access.&#8221; They didn&#8217;t think through what &#8220;edit access at the folder level&#8221; means across twelve projects. This is the GCP IAM trap that catches teams coming from AWS: the hierarchy feels like an organizational convenience feature, not an access control mechanism. It&#8217;s both.</p>
<hr />
<h2 id="the-resource-hierarchy-not-just-org-structure">The Resource Hierarchy — Not Just Org Structure</h2>
<p>GCP&#8217;s resource hierarchy is the backbone of its IAM model:</p>
<pre><code class="" data-line="">Organization  (e.g., company.com)
  └── Folder  (e.g., Production, Development, Shared-Services)
        └── Folder  (nested, optional — up to 10 levels)
              └── Project  (unit of resource ownership and billing)
                    └── Resource  (GCE instance, GCS bucket, Cloud SQL, BigQuery, etc.)
</code></pre>
<p>The critical rule: <strong>IAM bindings at any level inherit downward to every node below</strong>.</p>
<pre><code class="" data-line="">Org IAM binding:
  alice@company.com → roles/viewer (org-level)
    ↓ inherited by
  Folder: Production
    ↓ inherited by
  Project: prod-web-app
    ↓ inherited by
  GCS bucket &quot;prod-assets&quot;

Result: alice can list and read resources across the ENTIRE org,
        across every folder, every project, every resource.
        Even if none of those resources have a direct binding for alice.
</code></pre>
<p><code class="" data-line="">roles/viewer</code> at the org level sounds benign — it&#8217;s just read access. But read access to everything in the organization, including infrastructure configurations, customer data exports in GCS, BigQuery analytics, Cloud SQL connection details, and Kubernetes cluster configs. Not benign.</p>
<p>Before making any binding above the project level, trace it down. Ask: what does this role grant, and at every project and resource below this folder, am I comfortable with that?</p>
<pre><code class="" data-line=""># Understand your org structure before making changes
gcloud organizations list

gcloud resource-manager folders list --organization=ORG_ID

gcloud projects list --filter=&quot;parent.id=FOLDER_ID&quot;

# See all existing bindings at the org level — do this regularly
gcloud organizations get-iam-policy ORG_ID --format=json | jq &#039;.bindings[]&#039;
</code></pre>
<hr />
<h2 id="member-types-who-can-hold-a-binding">Member Types — Who Can Hold a Binding</h2>
<p>GCP uses the term <strong>member</strong> (being renamed to <strong>principal</strong>) for the identity in a binding:</p>
<table>
<thead>
<tr>
<th>Member Type</th>
<th>Format</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Google Account</td>
<td><code class="" data-line="">user:alice@company.com</code></td>
<td>Individual Google/Workspace account</td>
</tr>
<tr>
<td>Service Account</td>
<td><code class="" data-line="">serviceAccount:sa@project.iam.gserviceaccount.com</code></td>
<td>Machine identity</td>
</tr>
<tr>
<td>Google Group</td>
<td><code class="" data-line="">group:team@company.com</code></td>
<td>Workspace group</td>
</tr>
<tr>
<td>Workspace Domain</td>
<td><code class="" data-line="">domain:company.com</code></td>
<td>All users in a Workspace domain</td>
</tr>
<tr>
<td>All Authenticated</td>
<td><code class="" data-line="">allAuthenticatedUsers</code></td>
<td>Any authenticated Google identity — extremely broad</td>
</tr>
<tr>
<td>All Users</td>
<td><code class="" data-line="">allUsers</code></td>
<td>Anonymous + authenticated — public access</td>
</tr>
<tr>
<td>Workload Identity</td>
<td><code class="" data-line="">principal://iam.googleapis.com/...</code></td>
<td>External workloads via WIF</td>
</tr>
</tbody>
</table>
<p>The ones that have caused data exposure incidents: <code class="" data-line="">allAuthenticatedUsers</code> and <code class="" data-line="">allUsers</code>. Any GCS bucket or GCP resource bound to <code class="" data-line="">allAuthenticatedUsers</code> is accessible to any of the ~3 billion Google accounts in existence. I have seen production customer data exposed this way. A developer testing a public CDN pattern applied the binding to the wrong bucket.</p>
<p>Audit for these regularly:</p>
<pre><code class="" data-line=""># Find any project-level binding with allUsers or allAuthenticatedUsers
gcloud projects get-iam-policy my-project --format=json \
  | jq &#039;.bindings[] | select(.members[] | contains(&quot;allUsers&quot;) or contains(&quot;allAuthenticatedUsers&quot;))&#039;

# Check all GCS buckets in a project for public access
gsutil iam get gs://BUCKET_NAME \
  | grep -E &quot;(allUsers|allAuthenticatedUsers)&quot;
</code></pre>
<hr />
<h2 id="role-types-choose-the-right-granularity">Role Types — Choose the Right Granularity</h2>
<h3 id="basic-primitive-roles-dont-use-in-production">Basic (Primitive) Roles — Don&#8217;t Use in Production</h3>
<pre><code class="" data-line="">roles/viewer   → read access to most resources across the entire project
roles/editor   → read + write to most resources
roles/owner    → full access including IAM management
</code></pre>
<p>These are legacy roles from before GCP had service-specific roles. <code class="" data-line="">roles/editor</code> is particularly dangerous because it grants write access across almost every GCP service in the project. Use it in production and you have no meaningful separation of duties between your services.</p>
<p>I&#8217;ve seen <code class="" data-line="">roles/editor</code> granted to a data pipeline service account because &#8220;it needed access to BigQuery, Cloud Storage, and Pub/Sub.&#8221; All three of those have predefined roles. Three specific bindings. Instead: one broad role that also grants access to Cloud SQL, Kubernetes, Secret Manager, and Compute Engine — none of which the pipeline needed.</p>
<h3 id="predefined-roles-the-default-correct-choice">Predefined Roles — The Default Correct Choice</h3>
<p>Service-specific roles managed and updated by Google. For most use cases, these are the right choice:</p>
<pre><code class="" data-line=""># Find predefined roles for Cloud Storage
gcloud iam roles list --filter=&quot;name:roles/storage&quot; --format=&quot;table(name,title)&quot;
# roles/storage.objectViewer   — read objects (not list buckets)
# roles/storage.objectCreator  — create objects, cannot read or delete
# roles/storage.objectAdmin    — full object control
# roles/storage.admin          — full bucket + object control (much broader)

# See exactly what permissions a predefined role includes
gcloud iam roles describe roles/storage.objectViewer
</code></pre>
<p>The distinction between <code class="" data-line="">roles/storage.objectViewer</code> and <code class="" data-line="">roles/storage.admin</code> is the difference between &#8220;can read objects&#8221; and &#8220;can read objects, create objects, delete objects, and modify bucket IAM policies.&#8221; Use the narrowest role that covers the actual need.</p>
<h3 id="custom-roles-when-predefined-is-still-too-broad">Custom Roles — When Predefined Is Still Too Broad</h3>
<p>When you need finer control than any predefined role offers, create a custom role:</p>
<pre><code class="" data-line="">cat &gt; custom-log-reader.yaml &lt;&lt; &#039;EOF&#039;
title: &quot;Log Reader&quot;
description: &quot;Read application logs from Cloud Logging — nothing else&quot;
stage: &quot;GA&quot;
includedPermissions:
  - logging.logEntries.list
  - logging.logs.list
  - logging.logMetrics.get
  - logging.logMetrics.list
EOF

# Create at project level (available within one project)
gcloud iam roles create LogReader \
  --project=my-project \
  --file=custom-log-reader.yaml

# Or at org level (reusable across projects in the org)
gcloud iam roles create LogReader \
  --organization=ORG_ID \
  --file=custom-log-reader.yaml

# Grant the custom role
gcloud projects add-iam-policy-binding my-project \
  --member=&quot;serviceAccount:log-reader@my-project.iam.gserviceaccount.com&quot; \
  --role=&quot;projects/my-project/roles/LogReader&quot;
</code></pre>
<p>Custom roles have an operational overhead: when Google adds new permissions to a service, predefined roles are updated automatically. Custom roles are not — you have to update them manually. For roles like &#8220;Log Reader&#8221; that are unlikely to need new permissions, this isn&#8217;t a concern. For roles like &#8220;App Admin&#8221; that span many services, it becomes a maintenance burden.</p>
<hr />
<h2 id="iam-policy-bindings-how-access-is-actually-granted">IAM Policy Bindings — How Access Is Actually Granted</h2>
<p>The mechanism for granting access in GCP is adding a binding to a resource&#8217;s IAM policy. A binding is: <code class="" data-line="">member + role + (optional condition)</code>.</p>
<pre><code class="" data-line=""># Grant a role on a project (all resources in the project inherit this)
gcloud projects add-iam-policy-binding my-project \
  --member=&quot;user:alice@company.com&quot; \
  --role=&quot;roles/storage.objectViewer&quot;

# Grant on a specific GCS bucket (narrower — only this bucket)
gcloud storage buckets add-iam-policy-binding gs://prod-assets \
  --member=&quot;serviceAccount:app@my-project.iam.gserviceaccount.com&quot; \
  --role=&quot;roles/storage.objectViewer&quot;

# Grant on a specific BigQuery dataset
bq update --add_iam_policy_binding \
  --member=&quot;group:analysts@company.com&quot; \
  --role=&quot;roles/bigquery.dataViewer&quot; \
  my-project:analytics_dataset

# View the current IAM policy on a project
gcloud projects get-iam-policy my-project --format=json

# View a specific resource&#039;s policy
gcloud storage buckets get-iam-policy gs://prod-assets
</code></pre>
<p>The choice between project-level and resource-level binding has real consequences. A binding on the GCS bucket affects only that bucket. A binding at the project level affects the bucket AND every other resource in the project. In practice, default to the most specific scope available. Only move up the hierarchy when the alternative is an unmanageable number of bindings.</p>
<h3 id="conditional-bindings-time-limited-and-context-scoped-access">Conditional Bindings — Time-Limited and Context-Scoped Access</h3>
<p>Conditions scope when a binding applies. They use CEL (Common Expression Language):</p>
<pre><code class="" data-line=""># Temporary access for a contractor — automatically expires
gcloud projects add-iam-policy-binding my-project \
  --member=&quot;user:contractor@external.com&quot; \
  --role=&quot;roles/storage.objectViewer&quot; \
  --condition=&quot;expression=request.time &lt; timestamp(&#039;2026-06-30T00:00:00Z&#039;),title=Contractor access Q2 2026&quot;

# Access only from corporate network
gcloud projects add-iam-policy-binding my-project \
  --member=&quot;user:alice@company.com&quot; \
  --role=&quot;roles/bigquery.admin&quot; \
  --condition=&quot;expression=request.origin.ip.startsWith(&#039;10.0.&#039;),title=Corp network only&quot;
</code></pre>
<p>Temporary access that automatically expires is one of the most practical applications of conditional bindings. Instead of &#8220;I&#8217;ll grant access and remember to remove it,&#8221; you set an expiry and it removes itself. The cognitive overhead of tracking temporary grants doesn&#8217;t disappear — you still need to know the grant exists — but the risk of it outliving its purpose drops significantly.</p>
<hr />
<h2 id="service-accounts-gcps-machine-identity">Service Accounts — GCP&#8217;s Machine Identity</h2>
<p>Service accounts are the machine identity in GCP. They should be used for every workload that needs to call GCP APIs — GCE instances, GKE pods, Cloud Functions, Cloud Run services.</p>
<pre><code class="" data-line=""># Create a service account
gcloud iam service-accounts create app-backend \
  --display-name=&quot;App Backend Service Account&quot; \
  --project=my-project

SA_EMAIL=&quot;app-backend@my-project.iam.gserviceaccount.com&quot;

# Grant it the specific role it needs — on the specific resource it needs
gcloud storage buckets add-iam-policy-binding gs://app-assets \
  --member=&quot;serviceAccount:${SA_EMAIL}&quot; \
  --role=&quot;roles/storage.objectViewer&quot;

# Attach to a GCE instance
gcloud compute instances create my-vm \
  --service-account=&quot;${SA_EMAIL}&quot; \
  --scopes=&quot;cloud-platform&quot; \
  --zone=us-central1-a
</code></pre>
<p>From inside the VM, Application Default Credentials (ADC) handles authentication automatically:</p>
<pre><code class="" data-line=""># From the VM — ADC uses the attached SA without any credential configuration
gcloud auth application-default print-access-token

# Or via the metadata server directly
curl -H &quot;Metadata-Flavor: Google&quot; \
  &quot;http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token&quot;
</code></pre>
<h3 id="service-account-keys-the-antipattern-to-avoid">Service Account Keys — The Antipattern to Avoid</h3>
<p>A service account key is a JSON file containing a private key. It&#8217;s long-lived, it doesn&#8217;t expire automatically, and if it leaks it gives an attacker persistent access as that service account until someone discovers and revokes it.</p>
<pre><code class="" data-line=""># Creating a key — only if there is genuinely no alternative
gcloud iam service-accounts keys create key.json --iam-account=&quot;${SA_EMAIL}&quot;
# This generates a long-lived credential. It will exist until explicitly deleted.

# List all active keys — do this in every audit
gcloud iam service-accounts keys list --iam-account=&quot;${SA_EMAIL}&quot;

# Delete a key
gcloud iam service-accounts keys delete KEY_ID --iam-account=&quot;${SA_EMAIL}&quot;
</code></pre>
<p>In the GCP environment I mentioned earlier — the one with <code class="" data-line="">roles/editor</code> at the folder level — I also found 23 service account key files downloaded across the team&#8217;s laptops over 18 months. Nobody had a complete list of which keys were still valid and where they were stored. Several were for accounts that no longer existed. That&#8217;s not a hypothetical attack surface. It&#8217;s a breach waiting for a laptop to be stolen.</p>
<p><strong>Never create service account keys when:</strong><br />
&#8211; Code runs on GCE/GKE/Cloud Run/Cloud Functions — use the attached service account and ADC<br />
&#8211; Code runs in GitHub Actions — use Workload Identity Federation<br />
&#8211; Code runs on-premises with Kubernetes — use Workload Identity Federation with OIDC</p>
<h3 id="service-account-impersonation-the-right-alternative-to-keys">Service Account Impersonation — The Right Alternative to Keys</h3>
<p>Instead of downloading a key, grant a user or service account permission to impersonate the service account. They generate a short-lived token, not a permanent credential:</p>
<pre><code class="" data-line=""># Allow alice to impersonate the service account
gcloud iam service-accounts add-iam-policy-binding &quot;${SA_EMAIL}&quot; \
  --member=&quot;user:alice@company.com&quot; \
  --role=&quot;roles/iam.serviceAccountTokenCreator&quot;

# Alice generates a token for the SA — no key file, short-lived
gcloud auth print-access-token --impersonate-service-account=&quot;${SA_EMAIL}&quot;

# Or configure ADC to use impersonation
export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=&quot;${SA_EMAIL}&quot;
gcloud storage ls gs://app-assets  # runs as the SA
</code></pre>
<p>This is the right model for humans who need to act as service accounts for debugging or deployment: impersonate, use, done. The token expires. No file to manage.</p>
<hr />
<h2 id="workload-identity-federation-credentials-eliminated">Workload Identity Federation — Credentials Eliminated</h2>
<p>The cleanest solution for any workload running outside GCP that needs to call GCP APIs: Workload Identity Federation. The external workload authenticates with its native identity (a GitHub Actions OIDC JWT, an AWS IAM role, a Kubernetes service account token), exchanges it for a short-lived GCP access token, and never handles a service account key.</p>
<pre><code class="" data-line=""># Create a Workload Identity Pool
gcloud iam workload-identity-pools create &quot;github-actions-pool&quot; \
  --project=my-project \
  --location=global \
  --display-name=&quot;GitHub Actions WIF Pool&quot;

# Create a provider (GitHub OIDC)
gcloud iam workload-identity-pools providers create-oidc &quot;github-provider&quot; \
  --project=my-project \
  --location=global \
  --workload-identity-pool=&quot;github-actions-pool&quot; \
  --issuer-uri=&quot;https://token.actions.githubusercontent.com&quot; \
  --attribute-mapping=&quot;google.subject=assertion.sub,attribute.repository=assertion.repository&quot; \
  --attribute-condition=&quot;assertion.repository_owner == &#039;my-org&#039;&quot;

# Allow a specific GitHub repo to impersonate the SA
gcloud iam service-accounts add-iam-policy-binding &quot;${SA_EMAIL}&quot; \
  --role=&quot;roles/iam.workloadIdentityUser&quot; \
  --member=&quot;principalSet://iam.googleapis.com/projects/PROJECT_NUM/locations/global/workloadIdentityPools/github-actions-pool/attribute.repository/my-org/my-repo&quot;
</code></pre>
<p>GitHub Actions workflow — no key files, no secrets stored in GitHub:</p>
<pre><code class="" data-line="">jobs:
  deploy:
    permissions:
      id-token: write   # required for OIDC token request
      contents: read
    steps:
      - uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: &quot;projects/PROJECT_NUM/locations/global/workloadIdentityPools/github-actions-pool/providers/github-provider&quot;
          service_account: &quot;app-backend@my-project.iam.gserviceaccount.com&quot;

      - run: gcloud storage cp dist/ gs://app-assets/ --recursive
</code></pre>
<p>The OIDC JWT from GitHub is presented to GCP, which verifies it against GitHub&#8217;s public keys, checks the attribute mapping and condition (only the specified repo can use this), and issues a short-lived GCP access token. The credential exists for the duration of the job and is then gone.</p>
<hr />
<h2 id="iam-deny-policies-org-wide-guardrails">IAM Deny Policies — Org-Wide Guardrails</h2>
<p>GCP added standalone deny policies separate from bindings. They override grants:</p>
<pre><code class="" data-line="">cat &gt; deny-iam-escalation.json &lt;&lt; &#039;EOF&#039;
{
  &quot;displayName&quot;: &quot;Deny IAM escalation permissions to non-admins&quot;,
  &quot;rules&quot;: [{
    &quot;denyRule&quot;: {
      &quot;deniedPrincipals&quot;: [&quot;principalSet://goog/group/developers@company.com&quot;],
      &quot;deniedPermissions&quot;: [
        &quot;iam.googleapis.com/roles.create&quot;,
        &quot;iam.googleapis.com/roles.update&quot;,
        &quot;iam.googleapis.com/serviceAccounts.actAs&quot;
      ]
    }
  }]
}
EOF

gcloud iam policies create deny-iam-escalation-policy \
  --attachment-point=&quot;cloudresourcemanager.googleapis.com/projects/my-project&quot; \
  --policy-file=deny-iam-escalation.json
</code></pre>
<p><code class="" data-line="">iam.serviceAccounts.actAs</code> is worth calling out specifically. It&#8217;s the GCP equivalent of AWS&#8217;s <code class="" data-line="">iam:PassRole</code> — it allows an identity to make a service act as a specified service account. If a developer can call <code class="" data-line="">actAs</code> on a high-privileged service account, they can launch a GCE instance using that service account and then operate with its permissions. Same privilege escalation pattern as <code class="" data-line="">iam:PassRole</code>, different name. Deny it for anyone who doesn&#8217;t explicitly need it.</p>
<hr />
<h2 id="production-gotchas"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Production Gotchas</h2>
<p><strong><code class="" data-line="">roles/editor</code> at folder level is a blast radius waiting to happen</strong><br />
The role sounds like &#8220;edit access.&#8221; At folder level it means edit access to every service in every project under that folder — including services nobody thought to trace. Always scope to the specific project or resource, never a folder unless the use case explicitly requires it.</p>
<p><strong><code class="" data-line="">allAuthenticatedUsers</code> on a GCS bucket is public to 3 billion accounts</strong><br />
Any Google account — personal Gmail included — qualifies as &#8220;authenticated.&#8221; I&#8217;ve seen production customer data exposed this way while a developer tested a CDN pattern on the wrong bucket. Audit for these bindings before they become a breach notification.</p>
<p><strong>Service account keys accumulate and nobody tracks them</strong><br />
In every GCP environment I&#8217;ve audited that allowed SA key creation, there were active keys for accounts that no longer existed, stored on laptops with no central inventory. Keys don&#8217;t expire. Audit with <code class="" data-line="">gcloud iam service-accounts keys list</code> across every SA in every project.</p>
<p><strong><code class="" data-line="">iam.serviceAccounts.actAs</code> is a privilege escalation path</strong><br />
If a principal can call <code class="" data-line="">actAs</code> on a high-privileged SA, they can launch a GCE instance with that SA and operate with its full permissions — without ever being directly granted those permissions. Block this with a deny policy for everyone who doesn&#8217;t explicitly need it.</p>
<p><strong>Org-level <code class="" data-line="">roles/viewer</code> is not a safe broad grant</strong><br />
Read access to every project config, every service configuration, every infrastructure metadata object across your entire GCP estate is not a benign grant. Treat any binding above the project level as high-blast-radius, regardless of the role.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<pre><code class="" data-line=""># Audit org and folder structure before any high-level change
gcloud organizations list
gcloud resource-manager folders list --organization=ORG_ID
gcloud projects list --filter=&quot;parent.id=FOLDER_ID&quot;

# Inspect all bindings at org level
gcloud organizations get-iam-policy ORG_ID --format=json | jq &#039;.bindings[]&#039;

# Find allUsers / allAuthenticatedUsers in a project
gcloud projects get-iam-policy PROJECT_ID --format=json \
  | jq &#039;.bindings[] | select(.members[] | contains(&quot;allUsers&quot;) or contains(&quot;allAuthenticatedUsers&quot;))&#039;

# Check a GCS bucket for public access
gsutil iam get gs://BUCKET_NAME | grep -E &quot;(allUsers|allAuthenticatedUsers)&quot;

# Audit all user-managed SA keys across a project
gcloud iam service-accounts list --project=PROJECT_ID --format=&quot;value(email)&quot; \
  | xargs -I{} gcloud iam service-accounts keys list --iam-account={} --managed-by=user

# List predefined roles for a service
gcloud iam roles list --filter=&quot;name:roles/storage&quot; --format=&quot;table(name,title)&quot;

# Inspect what permissions a role actually includes
gcloud iam roles describe roles/storage.objectViewer

# Grant time-limited access with conditional binding
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member=&quot;user:contractor@external.com&quot; \
  --role=&quot;roles/storage.objectViewer&quot; \
  --condition=&quot;expression=request.time &lt; timestamp(&#039;2026-06-30T00:00:00Z&#039;),title=Contractor Q2 2026&quot;

# Enable SA impersonation (avoids key creation)
gcloud iam service-accounts add-iam-policy-binding SA_EMAIL \
  --member=&quot;user:alice@company.com&quot; \
  --role=&quot;roles/iam.serviceAccountTokenCreator&quot;
</code></pre>
<hr />
<h2 id="framework-alignment">Framework Alignment</h2>
<table>
<thead>
<tr>
<th>Framework</th>
<th>Reference</th>
<th>What It Covers Here</th>
</tr>
</thead>
<tbody>
<tr>
<td>CISSP</td>
<td>Domain 5 — Identity and Access Management</td>
<td>GCP&#8217;s hierarchical model and service account patterns are the primary IAM constructs for GCP environments</td>
</tr>
<tr>
<td>CISSP</td>
<td>Domain 3 — Security Architecture</td>
<td>Resource hierarchy design determines access inheritance — architectural decisions with direct security implications</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.15 Access control</td>
<td>GCP IAM bindings are the technical implementation of access control policy in GCP environments</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.18 Access rights</td>
<td>Service account provisioning, conditional bindings with expiry, and workload identity federation</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>8.2 Privileged access rights</td>
<td>Folder/org-level bindings and basic roles represent the highest-risk privilege grants in GCP</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.1</td>
<td>IAM bindings and Workload Identity Federation address machine identity controls for CC6.1</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.3</td>
<td>Conditional bindings with time-bound expiry directly satisfy access removal requirements</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>GCP IAM is hierarchical — bindings inherit downward; a binding at org or folder level has much larger scope than it appears</li>
<li>Basic roles (viewer/editor/owner) are too coarse for production; use predefined or custom roles and grant at the narrowest scope</li>
<li>Service account keys are a long-lived credential antipattern; use ADC on GCP infrastructure, impersonation for humans, and Workload Identity Federation for external workloads</li>
<li><code class="" data-line="">allAuthenticatedUsers</code> and <code class="" data-line="">allUsers</code> bindings expose resources to the internet — audit for these in every environment</li>
<li><code class="" data-line="">iam.serviceAccounts.actAs</code> is a privilege escalation vector — treat it like <code class="" data-line="">iam:PassRole</code></li>
<li>Conditional bindings with expiry dates are better than &#8220;I&#8217;ll remember to remove this later&#8221;</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>EP06 covers Azure RBAC and Entra ID — the most directory-centric of the three models, where Active Directory&#8217;s 25 years of enterprise history shapes both the strengths and the complexity of Azure&#8217;s access control.</p>
<p><em>Next: <a href="/azure-rbac-entra-id-guide/">Azure RBAC Scopes</a> — Management Groups, Subscriptions, and how role inheritance works across the Microsoft estate.</em></p>
<p>Get EP06 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe/">subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&amp;linkname=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fgcp-iam-deep-dive%2F&#038;title=GCP%20IAM%20Policy%20Inheritance%3A%20How%20the%20Resource%20Hierarchy%20Controls%20Access" data-a2a-url="https://linuxcent.com/gcp-iam-deep-dive/" data-a2a-title="GCP IAM Policy Inheritance: How the Resource Hierarchy Controls Access"></a></p><p>The post <a href="https://linuxcent.com/gcp-iam-deep-dive/">GCP IAM Policy Inheritance: How the Resource Hierarchy Controls Access</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/gcp-iam-deep-dive/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1477</post-id>	</item>
		<item>
		<title>What Is Cloud IAM — and Why Every API Call Depends on It</title>
		<link>https://linuxcent.com/what-is-cloud-iam/</link>
					<comments>https://linuxcent.com/what-is-cloud-iam/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Sat, 11 Apr 2026 12:19:03 +0000</pubDate>
				<category><![CDATA[Cloud IAM]]></category>
		<category><![CDATA[AWS IAM]]></category>
		<category><![CDATA[Azure IAM]]></category>
		<category><![CDATA[Cloud Security]]></category>
		<category><![CDATA[GCP IAM]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[Identity and Access Management]]></category>
		<category><![CDATA[Infrastructure Security]]></category>
		<guid isPermaLink="false">https://linuxcent.com/ep01-what-is-iam-the-identity-problem-in-modern-infrastructure/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 11</span> <span class="rt-label rt-postfix">minutes</span></span>IAM controls who can access what in your cloud environment. Learn the core concepts — identities, principals, policies, and why cloud IAM is deny-by-default.</p>
<p>The post <a href="https://linuxcent.com/what-is-cloud-iam/">What Is Cloud IAM — and Why Every API Call Depends on It</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 11</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<p><strong>What Is Cloud IAM</strong> → <a href="/authentication-vs-authorization-iam/">Authentication vs Authorization</a> → <a href="/iam-roles-policies-permissions-explained/">IAM Roles vs Policies</a> → <a href="/aws-iam-deep-dive/">AWS IAM Deep Dive</a> → <a href="/gcp-iam-deep-dive/">GCP Resource Hierarchy IAM</a> → <a href="/azure-rbac-entra-id-guide/">Azure RBAC Scopes</a></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li><strong>Cloud IAM</strong> is the system that decides whether any API call is allowed or denied — deny by default, explicit Allow required at every layer</li>
<li>Every API call answers four questions: Who? (Identity) What? (Action) On what? (Resource) Under what conditions? (Context)</li>
<li>Two identity types in every cloud account: human (engineers) and machine (Lambda, EC2, Kubernetes pods) — machine identities outnumber human by 10:1 in most production environments</li>
<li>AWS, GCP, and Azure share the same model: deny-by-default, policy-driven, principal-based — different syntax, same mental model</li>
<li>The gap between granted and used permissions is where attackers move — the average IAM entity uses under 5% of its granted permissions</li>
<li>IAM failure has two modes: over-permissioned (&#8220;it works&#8221;) and over-restricted (&#8220;it&#8217;s secure, engineers work around it&#8221;) — both end in incidents</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">                        WHAT IS CLOUD IAM?

  Every API call in AWS, GCP, or Azure answers four questions:

  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
  │    WHO?     │   │   WHAT?     │   │  ON WHAT?   │   │  UNDER      │
  │             │   │             │   │             │   │  WHAT?      │
  │  Identity / │   │  Action /   │   │  Resource   │   │             │
  │  Principal  │   │  Permission │   │             │   │  Condition  │
  │             │   │             │   │             │   │             │
  │ IAM Role    │   │ s3:GetObject│   │ arn:aws:s3: │   │ MFA: true   │
  │ Svc Account │   │ ec2:Start   │   │ ::prod-data │   │ IP: 10.0/8  │
  │ Managed     │   │ iam:        │   │ /exports/*  │   │ Time: 09-17 │
  │ Identity    │   │   PassRole  │   │             │   │             │
  └─────────────┘   └─────────────┘   └─────────────┘   └─────────────┘
        └────────────────┴────────────────┴────────────────┘
                                  │
                     ┌────────────▼────────────┐
                     │    IAM Policy Engine    │
                     │    deny by default      │
                     │                         │
                     │  Explicit ALLOW?   ─────┼──→  PERMIT
                     │  Explicit DENY?    ─────┼──→  DENY (overrides Allow)
                     │  No matching rule? ─────┼──→  DENY (implicit)
                     └─────────────────────────┘
</code></pre>
<p>Cloud IAM is the answer to a question every growing infrastructure team hits: at scale, how do you know <em>who can do what, why they can do it, and whether they still should?</em></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>Cloud IAM (Identity and Access Management) is the control plane for access in every major cloud provider. Every API call — reading a file, starting an instance, invoking a function — goes through an IAM evaluation. The result is binary: explicit Allow or deny. There is no implicit access. Nothing is open by default. This is what makes cloud IAM fundamentally different from the access models that came before it.</p>
<p>Understanding <em>why</em> it works that way requires tracing how access control evolved — and what kept breaking at each stage.</p>
<p>A few years into my career managing Linux infrastructure, I was handed a production server audit. The task was straightforward: find out who had access to what. I pulled <code class="" data-line="">/etc/passwd</code>, checked the sudoers file, reviewed SSH authorized_keys across the fleet.</p>
<p>Three days later, I had a spreadsheet nobody wanted to read.</p>
<p>The problem wasn&#8217;t that the access was wrong. Most of it was fine. The problem was that nobody — not the team lead, not the security team, not the engineers who&#8217;d been there five years — could tell me <em>why</em> a particular account had access to a particular server. It had accumulated. People joined, got access, changed teams, left. The access stayed.</p>
<p>That was a 40-server fleet in 2012.</p>
<p>Fast-forward to a cloud environment today: you might have 50 engineers, 300 Lambda functions, 20 microservices, CI/CD pipelines, third-party integrations, compliance scanners — all making API calls, all needing access to something. The identity sprawl problem I spent three days auditing manually on 40 servers now exists at a scale where manual auditing isn&#8217;t even a conversation.</p>
<p>This is the problem Identity and Access Management exists to solve. Not just in theory — in practice, at the scale cloud infrastructure demands.</p>
<hr />
<h2 id="how-we-got-here-the-evolution-of-access-control">How We Got Here — The Evolution of Access Control</h2>
<p>To understand <em>why</em> cloud IAM works the way it does, you need to trace how access control evolved. The design decisions in AWS IAM, GCP, and Azure didn&#8217;t come out of nowhere. They&#8217;re answers to lessons learned the hard way across decades of broken systems.</p>
<h3 id="the-unix-model-1970s1990s-simple-and-sufficient">The Unix Model (1970s–1990s): Simple and Sufficient</h3>
<p>Unix got the fundamentals right early. Every resource (file, device, process) has an owner and a group. Every action is one of three: read, write, execute. Every user is either the owner, in the group, or everyone else.</p>
<pre><code class="" data-line="">-rw-r--r--  1 vamshi  engineers  4096 Apr 11 09:00 deploy.conf
# owner can read/write | group can read | others can read
</code></pre>
<p>For a single machine or a small network, this model is elegant. The permissions are visible in a <code class="" data-line="">ls -l</code>. Reasoning about access is straightforward. Auditing means reading a few files.</p>
<p>However, the cracks started showing when organizations grew. You&#8217;d add <code class="" data-line="">sudo</code> to give specific commands to specific users. Then sudoers files became 300 lines long. Then you&#8217;d have shared accounts because managing individual ones was &#8220;too much overhead.&#8221; Shared accounts mean no individual accountability. No accountability means no audit trail worth anything.</p>
<h3 id="the-directory-era-1990s2000s-centralise-or-collapse">The Directory Era (1990s–2000s): Centralise or Collapse</h3>
<p>As networks grew, every server managing its own <code class="" data-line="">/etc/passwd</code> became untenable. Enter <strong>LDAP</strong> and <strong>Active Directory</strong>. Instead of distributing identity management across every machine, you centralised it: one directory, one place to add users, one place to disable them when someone left.</p>
<p>This was a significant step forward. Onboarding got faster. Offboarding became reliable. Group membership drove access to resources across the network.</p>
<h3 id="why-groups-became-the-new-problem">Why Groups Became the New Problem</h3>
<p>But the permission model was still coarse. You were either in the Domain Admins group or you weren&#8217;t. &#8220;Read access to the file share&#8221; was a group. &#8220;Deploy to the staging web server&#8221; was a group. Managing fine-grained permissions at scale meant managing hundreds of groups, and the groups themselves became the audit nightmare.</p>
<p>I spent time in environments like this. The group named <code class="" data-line="">SG_Prod_App_ReadWrite_v2_FINAL</code> that nobody could explain. The AD group from a project that ended three years ago but was still in twenty user accounts. The contractor whose AD account was disabled but whose service account was still running a nightly job.</p>
<p>The directory model centralised identity. It didn&#8217;t solve the permissions sprawl problem.</p>
<h3 id="the-cloud-shift-20062014-everything-changes">The Cloud Shift (2006–2014): Everything Changes</h3>
<p>AWS launched EC2 in 2006. In 2011, AWS IAM went into general availability. That date matters — for the first five years of AWS, access control was primitive. Root accounts. Access keys. No roles.</p>
<p>Early AWS environments I&#8217;ve seen (and had to clean up) reflect this era: a single root account access key shared across a team, rotated manually on a shared spreadsheet. Static credentials in application config files. EC2 instances with AdministratorAccess because &#8220;it was easier at the time.&#8221;</p>
<h3 id="the-model-that-changed-everything">The Model That Changed Everything</h3>
<p>The AWS team understood what they&#8217;d built was dangerous. IAM in 2011 introduced the model that all three major cloud providers now share: <strong>deny-by-default, policy-driven, principal-based access control</strong>. Not &#8220;who is in which group.&#8221; The question became: which policy explicitly grants this specific action on this specific resource to this specific identity.</p>
<p>GCP launched its IAM model with a different flavour in 2012 — hierarchical, additive, binding-based. Azure RBAC came to general availability in 2014, built on top of Active Directory&#8217;s identity model.</p>
<p>By 2015, the modern cloud IAM era was established. The primitives existed. The problem shifted from &#8220;does IAM exist?&#8221; to &#8220;are we using it correctly?&#8221; — and most teams were not.</p>
<p>In practice, that question is still the right one to ask today.</p>
<hr />
<h2 id="the-problem-iam-actually-solves">The Problem IAM Actually Solves</h2>
<p>Here&#8217;s the honest version of what IAM is for, based on what I&#8217;ve seen go wrong without it.</p>
<p><strong>Without proper IAM, you get one of two outcomes:</strong></p>
<p>The first is what I call the <em>&#8220;it works&#8221;</em> environment. Everything runs. The developers are happy. Access requests take five minutes because everyone gets the same broad policy. And then a Lambda function&#8217;s execution role — which had <code class="" data-line="">s3:*</code> on <code class="" data-line="">*</code> because someone once needed to debug something — gets its credentials exposed through an SSRF vulnerability in the app it runs. That role can now read every bucket in the account, including the one with the customer database exports.</p>
<p>The second is the <em>&#8220;it&#8217;s secure&#8221;</em> environment. Access is locked down. Every request goes through a ticket. The ticket goes to a security team that approves it in three to five business days. Engineers work around it by storing credentials locally. The workarounds become the real access model. The formal IAM posture and the actual access posture diverge. The audit finds the formal one. Attackers find the real one.</p>
<p>IAM, done right, is the discipline of walking the line between those two outcomes. It&#8217;s not a product you buy or a feature you turn on. It&#8217;s a practice — a continuous process of defining what access exists, why it exists, and whether it&#8217;s still needed.</p>
<hr />
<h2 id="the-core-concepts-taught-not-listed">The Core Concepts — Taught, Not Listed</h2>
<p>Let me walk you through the vocabulary you need, grounded in what each concept means in practice.</p>
<h3 id="identity-who-is-making-this-request">Identity: Who Is Making This Request?</h3>
<p>An <strong>identity</strong> is any entity that can hold a credential and make requests. In cloud environments, identities split into two types:</p>
<p><strong>Human identities</strong> are engineers, operators, and developers. They authenticate via the console, CLI, or SDK. They should ideally authenticate through a central IdP (Okta, Google Workspace, Entra ID) using federation — more on that in <a href="/cloud-identity-federation-oidc-saml/">SAML vs OIDC: Which Federation Protocol Belongs in Your Cloud?</a>.</p>
<p><strong>Machine identities</strong> are everything else: Lambda functions, EC2 instances, Kubernetes pods, CI/CD pipelines, monitoring agents, data pipelines. In most production environments, machine identities outnumber human identities by 10:1 or more.</p>
<p>This ratio matters. When your security model is designed primarily for human access, the 90% of identities that are machines become an afterthought. That&#8217;s where access keys end up in environment variables, where Lambda functions get broad permissions because nobody thought carefully about what they actually need, where the real attack surface lives.</p>
<h3 id="principal-the-authenticated-identity-making-a-specific-request">Principal: The Authenticated Identity Making a Specific Request</h3>
<p>A <strong>principal</strong> is an identity that has been authenticated and is currently making a request. The distinction from &#8220;identity&#8221; is subtle but important: the principal includes the context of how the identity authenticated.</p>
<p>In AWS, an IAM role assumed by EC2, assumed by a Lambda, and assumed by a developer&#8217;s CLI session are three different principals — even if they all assume the same role. The session context, source, and expiration differ.</p>
<pre><code class="" data-line="">{
  &quot;Principal&quot;: {
    &quot;AWS&quot;: &quot;arn:aws:iam::123456789012:role/DataPipelineRole&quot;
  }
}
</code></pre>
<p>In GCP, the equivalent term is <strong>member</strong>. In Azure, it&#8217;s <strong>security principal</strong> — a user, group, service principal, or managed identity.</p>
<h3 id="resource-what-is-being-accessed">Resource: What Is Being Accessed?</h3>
<p>A <strong>resource</strong> is whatever is being acted upon. In AWS, every resource has an ARN (Amazon Resource Name) — a globally unique identifier.</p>
<pre><code class="" data-line="">arn:aws:s3:::customer-data-prod          # S3 bucket
arn:aws:s3:::customer-data-prod/*        # everything inside that bucket
arn:aws:ec2:ap-south-1:123456789012:instance/i-0abcdef1234567890
arn:aws:iam::123456789012:role/DataPipelineRole
</code></pre>
<p>The ARN structure tells you: service, region, account, resource type, resource name. Once you can read ARNs fluently, IAM policies become much less intimidating.</p>
<h3 id="action-what-is-being-done">Action: What Is Being Done?</h3>
<p>An <strong>action</strong> (AWS/Azure) or <strong>permission</strong> (GCP) is the operation being attempted. Cloud providers express these as <code class="" data-line="">service:Operation</code> strings:</p>
<pre><code class="" data-line=""># AWS
s3:GetObject           # read a specific object
s3:PutObject           # write an object
s3:DeleteObject        # delete an object — treat differently than read
iam:PassRole           # assign a role to a service — one of the most dangerous permissions
ec2:DescribeInstances  # list instances — often overlooked, but reveals infrastructure

# GCP
storage.objects.get
storage.objects.create
iam.serviceAccounts.actAs   # impersonate a service account — equivalent to iam:PassRole danger
</code></pre>
<p>When I audit IAM configurations, I pay special attention to any policy that includes <code class="" data-line="">iam:*</code>, <code class="" data-line="">iam:PassRole</code>, or wildcards like <code class="" data-line="">&quot;Action&quot;: &quot;*&quot;</code>. These are the permissions that let a compromised identity create new identities, assign itself more power, or impersonate other accounts. They&#8217;re the privilege escalation primitives — more on that in <a href="/cloud-iam-privilege-escalation/">AWS IAM Privilege Escalation: How iam:PassRole Leads to Full Compromise</a>.</p>
<h3 id="policy-the-document-that-connects-everything">Policy: The Document That Connects Everything</h3>
<p>A <strong>policy</strong> is a document that says: this principal can perform these actions on these resources, under these conditions.</p>
<pre><code class="" data-line="">{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [
    {
      &quot;Sid&quot;: &quot;ReadCustomerDataBucket&quot;,
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Action&quot;: [
        &quot;s3:GetObject&quot;,
        &quot;s3:ListBucket&quot;
      ],
      &quot;Resource&quot;: [
        &quot;arn:aws:s3:::customer-data-prod&quot;,
        &quot;arn:aws:s3:::customer-data-prod/*&quot;
      ]
    }
  ]
}
</code></pre>
<p>Notice what&#8217;s explicit here: the effect (<code class="" data-line="">Allow</code>), the exact actions (not <code class="" data-line="">s3:*</code>), and the exact resource (not <code class="" data-line="">*</code>). Every word in this document is a deliberate decision. The moment you start using wildcards to save typing, you&#8217;re writing technical debt that will come back as a security incident.</p>
<hr />
<h2 id="how-iam-actually-works-the-decision-flow">How IAM Actually Works — The Decision Flow</h2>
<p>When any API call hits a cloud service, an IAM engine evaluates it. Understanding this flow is the foundation of debugging access issues, and more importantly, of understanding why your security posture is what it is.</p>
<pre><code class="" data-line="">Request arrives:
  Action:    s3:PutObject
  Resource:  arn:aws:s3:::customer-data-prod/exports/2026-04-11.csv
  Principal: arn:aws:iam::123456789012:role/DataPipelineRole
  Context:   { source_ip: &quot;10.0.2.15&quot;, mfa: false, time: &quot;02:30 UTC&quot; }

IAM Engine evaluation (AWS):
  1. Is there an explicit Deny anywhere? → No
  2. Does the SCP (if any) allow this? → Yes
  3. Does the identity-based policy allow this? → Yes (via DataPipelinePolicy)
  4. Does the resource-based policy (bucket policy) allow or deny? → No explicit rule → implicit allow for same-account
  5. Is there a permissions boundary? → No
  Decision: ALLOW
</code></pre>
<p>The critical insight here: <strong>cloud IAM is deny-by-default</strong>. There is no implicit allow. If there is no policy that explicitly grants <code class="" data-line="">s3:PutObject</code> to this role on this bucket, the request fails. The only way in is through an explicit <code class="" data-line="">&quot;Effect&quot;: &quot;Allow&quot;</code>.</p>
<p>This is the opposite of how most traditional systems work. In a Unix permission model, if your file is world-readable (<code class="" data-line="">-r--r--r--</code>), anyone can read it unless you actively restrict them. In cloud IAM, nothing is accessible unless you actively grant it.</p>
<p>When I&#8217;m debugging an <code class="" data-line="">AccessDenied</code> error — and every engineer who works with cloud IAM spends significant time doing this — the mental model is always: &#8220;what is the chain of explicit Allows that should be granting this access, and at which layer is it missing?&#8221;</p>
<hr />
<h2 id="why-this-is-harder-than-it-looks">Why This Is Harder Than It Looks</h2>
<p>Understanding the concepts is the easy part. The hard part is everything that happens at organisational scale over time.</p>
<p><strong>Scale.</strong> A real AWS account in a growing company might have 600+ IAM roles, 300+ policies, and 40+ cross-account trust relationships. None of these were designed together. They evolved incrementally, each change made by someone who understood the context at the time and may have left the organisation since. The cumulative effect is an IAM configuration that no single person fully understands.</p>
<p><strong>Drift.</strong> IAM configs don&#8217;t stay clean. An engineer needs to debug a production issue at 2 AM and grants themselves broad access temporarily. The temporary access never gets revoked. Multiply that by a team of 20 over three years. I&#8217;ve audited environments where 60% of the permissions in a role had never been used — not once — in the 90-day CloudTrail window. That unused 60% is pure attack surface.</p>
<p><strong>The machine identity blind spot.</strong> Most IAM governance practices were built for human users. Service accounts, Lambda roles, and CI/CD pipeline identities get created rapidly and reviewed rarely. In my experience, these are the identities most likely to have excess permissions, least likely to be in the access review process, and most likely to be the initial foothold in a cloud breach.</p>
<p><strong>The gap between granted and used.</strong> That said, this one surprised me most when I first started doing cloud security work. AWS data from real customer accounts shows the average IAM entity uses less than 5% of its granted permissions. That 95% excess isn&#8217;t just waste — it&#8217;s attack surface. Every permission that exists but isn&#8217;t needed is a permission an attacker can use if they compromise that identity.</p>
<hr />
<h2 id="iam-across-aws-gcp-and-azure-the-conceptual-map">IAM Across AWS, GCP, and Azure — The Conceptual Map</h2>
<p>The three major providers implement IAM differently in syntax, but the same model underlies all of them. Once you understand one deeply, the others become a translation exercise.</p>
<table>
<thead>
<tr>
<th>Concept</th>
<th>AWS</th>
<th>GCP</th>
<th>Azure</th>
</tr>
</thead>
<tbody>
<tr>
<td>Identity store</td>
<td>IAM users / roles</td>
<td>Google accounts, Workspace</td>
<td>Entra ID</td>
</tr>
<tr>
<td>Machine identity</td>
<td>IAM Role (via instance profile or AssumeRole)</td>
<td>Service Account</td>
<td>Managed Identity</td>
</tr>
<tr>
<td>Access grant mechanism</td>
<td>Policy document attached to identity or resource</td>
<td>IAM binding on resource (member + role + condition)</td>
<td>Role Assignment (principal + role + scope)</td>
</tr>
<tr>
<td>Hierarchy</td>
<td>Account is the boundary; Org via SCPs</td>
<td>Org → Folder → Project → Resource</td>
<td>Tenant → Management Group → Subscription → Resource Group → Resource</td>
</tr>
<tr>
<td>Default stance</td>
<td>Deny</td>
<td>Deny</td>
<td>Deny</td>
</tr>
<tr>
<td>Wildcard risk</td>
<td><code class="" data-line="">&quot;Action&quot;: &quot;*&quot;</code> on <code class="" data-line="">&quot;Resource&quot;: &quot;*&quot;</code></td>
<td>Primitive roles (viewer/editor/owner)</td>
<td><code class="" data-line="">Owner</code> or <code class="" data-line="">Contributor</code> assigned broadly</td>
</tr>
</tbody>
</table>
<p>The hierarchy point is worth pausing on. AWS is relatively flat — the account is the primary security boundary. GCP&#8217;s hierarchy means a binding at the Organisation level propagates down to every project. Azure&#8217;s hierarchy means a role assignment at the Management Group level flows through every subscription beneath it.</p>
<p>The blast radius of a misconfiguration scales with how high in the hierarchy it sits.</p>
<p>This will matter in <a href="/gcp-iam-deep-dive/">GCP IAM Policy Inheritance</a> and <a href="/azure-rbac-entra-id-guide/">Azure RBAC Explained</a> when we go deep on GCP and Azure specifically. For now, the takeaway is: understand where in the hierarchy a permission is granted, because the same permission granted at the wrong level has a very different security implication.</p>
<hr />
<h2 id="framework-alignment">Framework Alignment</h2>
<p>If you&#8217;re mapping this episode to a control framework — for a compliance audit, a certification study, or building a security program — here&#8217;s where it lands:</p>
<table>
<thead>
<tr>
<th>Framework</th>
<th>Reference</th>
<th>What It Covers Here</th>
</tr>
</thead>
<tbody>
<tr>
<td>CISSP</td>
<td>Domain 1 — Security &amp; Risk Management</td>
<td>IAM as a risk reduction control; blast radius is a risk variable</td>
</tr>
<tr>
<td>CISSP</td>
<td>Domain 5 — Identity and Access Management</td>
<td>Direct implementation: who can do what, to which resources, under what conditions</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.15 Access control</td>
<td>Policy requirements for restricting access to information and systems</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.16 Identity management</td>
<td>Managing the full lifecycle of identities in the organization</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>5.18 Access rights</td>
<td>Provisioning, review, and removal of access rights</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.1</td>
<td>Logical access security controls to protect against unauthorized access</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.3</td>
<td>Access removal and review processes to limit unauthorized access</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>IAM evolved from Unix file permissions → directory services → cloud policy engines, driven by scale and the failure modes of each prior model</li>
<li>Cloud IAM is deny-by-default: every access requires an explicit Allow somewhere in the policy chain</li>
<li>Identities are human or machine; in production, machines dominate — and they&#8217;re the under-governed majority</li>
<li>A policy binds a principal to actions on resources; every word is a deliberate security decision</li>
<li>The hardest IAM problems aren&#8217;t technical — they&#8217;re organisational: drift, unused permissions, machine identities nobody owns, and access reviews that never happen</li>
<li>The gap between granted and used permissions is where attackers find room to move</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>Now that you understand what IAM is and why it exists, the next question is the one that trips up even experienced engineers: what&#8217;s the difference between authentication and authorization, and why does conflating them cause security failures?</p>
<p>EP02 works through both — how cloud providers implement each, where the boundary sits, and why getting this boundary wrong creates exploitable gaps.</p>
<p><em>Next: <a href="/authentication-vs-authorization-iam/">Authentication vs Authorization: AWS AccessDenied Explained</a></em></p>
<p>Get EP02 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe/">subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&amp;linkname=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fwhat-is-cloud-iam%2F&#038;title=What%20Is%20Cloud%20IAM%20%E2%80%94%20and%20Why%20Every%20API%20Call%20Depends%20on%20It" data-a2a-url="https://linuxcent.com/what-is-cloud-iam/" data-a2a-title="What Is Cloud IAM — and Why Every API Call Depends on It"></a></p><p>The post <a href="https://linuxcent.com/what-is-cloud-iam/">What Is Cloud IAM — and Why Every API Call Depends on It</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/what-is-cloud-iam/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1445</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: linuxcent.com @ 2026-09-01 13:05:48 by W3 Total Cache
-->