<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Access-Management on Tarragon</title><link>https://tarrragon.github.io/blog/tags/access-management/</link><description>Recent content in Access-Management on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 26 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/access-management/index.xml" rel="self" type="application/rss+xml"/><item><title>團隊權限分級與存取管理</title><link>https://tarrragon.github.io/blog/infra/02-identity-credentials/team-access-management/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/02-identity-credentials/team-access-management/</guid><description>&lt;p>IAM 的 role 與 policy 提供「某個身分能不能對某個資源做某件事」的技術機制（見&lt;a href="https://tarrragon.github.io/blog/infra/02-identity-credentials/iam-oidc-privilege-boundary/" data-link-title="身分與憑證地基 — IAM 模型、OIDC 短期憑證與權限邊界設計" data-link-desc="IAM 的 identity / policy / role 三元件、最小權限的持續收斂、用 OIDC 取代長期 access key，以及 SCP 與 Permissions Boundary 的環境隔離">身分與憑證地基&lt;/a>）。機制備妥後，下一個問題是組織層面的設計：團隊裡每個角色該拿到哪一級權限、臨時需要更高權限時怎麼提權、離職或合約結束時怎麼確保存取被回收。這些設計的目的是讓「誰能動什麼」在任何時間點都有可稽核的答案。&lt;/p>
&lt;h2 id="權限分級admin--operator--viewer">權限分級：admin / operator / viewer&lt;/h2>
&lt;p>團隊成員的日常操作權限用三級來劃分，每一級對應不同的操作範圍與風險。分級的依據是「這個角色的日常工作需要碰到什麼層級的資源」，不是職稱或年資。&lt;/p>
&lt;h3 id="admin">Admin&lt;/h3>
&lt;p>Admin 能修改 IAM policy、網路拓撲、帳號層級設定（Organizations、SCP、billing）。這是影響範圍最大的一級——一條 SCP 寫錯可以鎖死整個帳號的操作，一條 IAM policy 開太寬可以讓任何角色取得不該有的權限。&lt;/p>
&lt;p>持有 admin 權限的人數應該收斂到最少：通常是平台團隊的 1-2 人加上一個 break-glass 備援角色。Admin 權限不應該是某個人的「日常身分」——即使是平台工程師，日常操作也用 operator 等級，只有在需要改 IAM 或帳號設定時才 assume 到 admin role。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># Admin role 的信任政策：只允許特定 IAM user assume
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">data&lt;/span> &lt;span class="s2">&amp;#34;aws_iam_policy_document&amp;#34; &amp;#34;admin_trust&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="k">statement&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="n"> actions&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;sts:AssumeRole&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="k">principals&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="n"> type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;AWS&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="n"> identifiers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;arn:aws:iam::123456789012:user/platform-lead&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;arn:aws:iam::123456789012:user/platform-backup&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> &lt;span class="k">condition&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="n"> test&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Bool&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="n"> variable&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;aws:MultiFactorAuthPresent&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="n"> values&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_iam_role&amp;#34; &amp;#34;admin&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="n"> name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;infra-admin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="n"> assume_role_policy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">aws_iam_policy_document&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">admin_trust&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="n"> max_session_duration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">3600&lt;/span>&lt;span class="c1"> # 1 小時後自動失效
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>}&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>max_session_duration&lt;/code> 限制 assume 後的有效時間。Admin session 設 1 小時是讓操作者完成當次任務後權限自動回收，不需要手動登出。MFA 條件確保即使帳號密碼外洩，沒有第二因素也無法提權。&lt;/p>
&lt;h3 id="operator">Operator&lt;/h3>
&lt;p>Operator 能部署服務、修改應用層資源（ECS task、RDS parameter group、S3 lifecycle）、查看與操作日常維運所需的一切。多數工程師的日常身分落在這一級。&lt;/p>
&lt;p>Operator 的 policy 用 resource scope 限制它碰不到 IAM 和帳號層級設定——能改 ECS service 但不能改 ECS service 用的 IAM role，能改 RDS 參數但不能改 RDS 的 subnet group。這個邊界讓 operator 的操作失誤影響範圍停在服務層，不會擴散到地基層。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="k">data&lt;/span> &lt;span class="s2">&amp;#34;aws_iam_policy_document&amp;#34; &amp;#34;operator&amp;#34;&lt;/span> {&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1"> # 允許操作應用層資源
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">statement&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="n"> actions&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ecs:UpdateService&amp;#34;, &amp;#34;ecs:DescribeServices&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;rds:ModifyDBInstance&amp;#34;, &amp;#34;rds:DescribeDBInstances&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;s3:GetObject&amp;#34;, &amp;#34;s3:PutObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;logs:GetLogEvents&amp;#34;, &amp;#34;logs:FilterLogEvents&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="n"> resources&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;*&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> }&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"> # 明確拒絕碰 IAM 和帳號設定
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">statement&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="n"> effect&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Deny&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="n"> actions&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;iam:*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;organizations:*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;account:*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="n"> resources&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;*&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">}&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Deny 語句確保即使未來有人不小心把過寬的 managed policy attach 到 operator role，IAM 和帳號操作仍然被擋。Deny 在 IAM 評估中優先於 Allow。&lt;/p></description><content:encoded><![CDATA[<p>IAM 的 role 與 policy 提供「某個身分能不能對某個資源做某件事」的技術機制（見<a href="/blog/infra/02-identity-credentials/iam-oidc-privilege-boundary/" data-link-title="身分與憑證地基 — IAM 模型、OIDC 短期憑證與權限邊界設計" data-link-desc="IAM 的 identity / policy / role 三元件、最小權限的持續收斂、用 OIDC 取代長期 access key，以及 SCP 與 Permissions Boundary 的環境隔離">身分與憑證地基</a>）。機制備妥後，下一個問題是組織層面的設計：團隊裡每個角色該拿到哪一級權限、臨時需要更高權限時怎麼提權、離職或合約結束時怎麼確保存取被回收。這些設計的目的是讓「誰能動什麼」在任何時間點都有可稽核的答案。</p>
<h2 id="權限分級admin--operator--viewer">權限分級：admin / operator / viewer</h2>
<p>團隊成員的日常操作權限用三級來劃分，每一級對應不同的操作範圍與風險。分級的依據是「這個角色的日常工作需要碰到什麼層級的資源」，不是職稱或年資。</p>
<h3 id="admin">Admin</h3>
<p>Admin 能修改 IAM policy、網路拓撲、帳號層級設定（Organizations、SCP、billing）。這是影響範圍最大的一級——一條 SCP 寫錯可以鎖死整個帳號的操作，一條 IAM policy 開太寬可以讓任何角色取得不該有的權限。</p>
<p>持有 admin 權限的人數應該收斂到最少：通常是平台團隊的 1-2 人加上一個 break-glass 備援角色。Admin 權限不應該是某個人的「日常身分」——即使是平台工程師，日常操作也用 operator 等級，只有在需要改 IAM 或帳號設定時才 assume 到 admin role。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Admin role 的信任政策：只允許特定 IAM user assume
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">data</span> <span class="s2">&#34;aws_iam_policy_document&#34; &#34;admin_trust&#34;</span> {
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="k">statement</span> {
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">    actions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sts:AssumeRole&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">principals</span> {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">      type</span>        <span class="o">=</span> <span class="s2">&#34;AWS&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">      identifiers</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;arn:aws:iam::123456789012:user/platform-lead&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;arn:aws:iam::123456789012:user/platform-backup&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    }
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">condition</span> {
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">      test</span>     <span class="o">=</span> <span class="s2">&#34;Bool&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">      variable</span> <span class="o">=</span> <span class="s2">&#34;aws:MultiFactorAuthPresent&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">      values</span>   <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;true&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    }
</span></span><span class="line"><span class="ln">17</span><span class="cl">  }
</span></span><span class="line"><span class="ln">18</span><span class="cl">}
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="k">resource</span> <span class="s2">&#34;aws_iam_role&#34; &#34;admin&#34;</span> {
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">  name</span>               <span class="o">=</span> <span class="s2">&#34;infra-admin&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">  assume_role_policy</span> <span class="o">=</span> <span class="k">data</span><span class="p">.</span><span class="k">aws_iam_policy_document</span><span class="p">.</span><span class="k">admin_trust</span><span class="p">.</span><span class="k">json</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">  max_session_duration</span> <span class="o">=</span> <span class="m">3600</span><span class="c1">  # 1 小時後自動失效
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span>}</span></span></code></pre></div><p><code>max_session_duration</code> 限制 assume 後的有效時間。Admin session 設 1 小時是讓操作者完成當次任務後權限自動回收，不需要手動登出。MFA 條件確保即使帳號密碼外洩，沒有第二因素也無法提權。</p>
<h3 id="operator">Operator</h3>
<p>Operator 能部署服務、修改應用層資源（ECS task、RDS parameter group、S3 lifecycle）、查看與操作日常維運所需的一切。多數工程師的日常身分落在這一級。</p>
<p>Operator 的 policy 用 resource scope 限制它碰不到 IAM 和帳號層級設定——能改 ECS service 但不能改 ECS service 用的 IAM role，能改 RDS 參數但不能改 RDS 的 subnet group。這個邊界讓 operator 的操作失誤影響範圍停在服務層，不會擴散到地基層。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">data</span> <span class="s2">&#34;aws_iam_policy_document&#34; &#34;operator&#34;</span> {<span class="c1">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1">  # 允許操作應用層資源
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"></span>  <span class="k">statement</span> {
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">    actions</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="s2">&#34;ecs:UpdateService&#34;, &#34;ecs:DescribeServices&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="s2">&#34;rds:ModifyDBInstance&#34;, &#34;rds:DescribeDBInstances&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="s2">&#34;s3:GetObject&#34;, &#34;s3:PutObject&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="s2">&#34;logs:GetLogEvents&#34;, &#34;logs:FilterLogEvents&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">    resources</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;*&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  }<span class="c1">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1">  # 明確拒絕碰 IAM 和帳號設定
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span>  <span class="k">statement</span> {
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">    effect</span> <span class="o">=</span> <span class="s2">&#34;Deny&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">    actions</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="s2">&#34;iam:*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">      <span class="s2">&#34;organizations:*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">      <span class="s2">&#34;account:*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">    resources</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;*&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  }
</span></span><span class="line"><span class="ln">23</span><span class="cl">}</span></span></code></pre></div><p>Deny 語句確保即使未來有人不小心把過寬的 managed policy attach 到 operator role，IAM 和帳號操作仍然被擋。Deny 在 IAM 評估中優先於 Allow。</p>
<h3 id="viewer">Viewer</h3>
<p>Viewer 能讀取 Console、查 log、看 metric dashboard，但不能修改任何資源。適合的角色包括：值班但不需要改設定的 on-call、需要查 log 排查問題的 support 團隊、需要看資源狀態的管理層。</p>
<p>Viewer 用 AWS 的 managed policy <code>ReadOnlyAccess</code> 作為基線，再根據需要排除敏感資料的讀取（例如 Secrets Manager 的 <code>GetSecretValue</code>）。</p>
<p>三級的對應關係：</p>
<table>
  <thead>
      <tr>
          <th>級別</th>
          <th>能做什麼</th>
          <th>典型角色</th>
          <th>人數控制</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Admin</td>
          <td>改 IAM、網路、帳號設定</td>
          <td>平台 lead + break-glass</td>
          <td>2-3 人</td>
      </tr>
      <tr>
          <td>Operator</td>
          <td>部署、改服務設定、查 log</td>
          <td>工程師</td>
          <td>團隊規模</td>
      </tr>
      <tr>
          <td>Viewer</td>
          <td>讀 Console、查 log、看 metrics</td>
          <td>on-call、support、管理層</td>
          <td>依需求開放</td>
      </tr>
  </tbody>
</table>
<p>導入時程參考：三級權限的 IAM role 與 policy 建立約需 1-2 天，包含 trust policy 設定與初次分配。後續的權限變更走版本控制的 PR 流程，讓每次 policy 調整都有提案、審查與歷史紀錄（見<a href="/blog/infra/07-infra-as-pr/" data-link-title="模組七：infra 走 PR 流程與自動化護欄" data-link-desc="infra 變更走 PR → plan → review diff → 合併 → apply，配 fmt / validate / tflint / checkov / tfsec 與 Atlantis 自動化，讓基礎設施可審查、可回溯、可交接">infra 走 PR 流程</a>）。</p>
<h2 id="臨時提權break-glass">臨時提權（break-glass）</h2>
<p>Operator 在日常工作中偶爾需要 admin 層級的操作——排查一個涉及 IAM 的事故、緊急修改一條 security group 規則、回應安全事件。常態性地把 admin 權限開給所有 operator 會讓三級分級失效，但每次都等 admin 角色的人上線又太慢。Break-glass 流程處理的就是這個中間地帶。</p>
<h3 id="機制">機制</h3>
<p>Break-glass 的實作是一個平時不被 assume 的 admin role，加上一套提權紀錄。Operator 在需要時 assume 這個 role，取得一段時效有限的 admin session。這個 assume 動作會在 CloudTrail 留下紀錄（誰、什麼時候、session 多長），事後可稽核。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">resource</span> <span class="s2">&#34;aws_iam_role&#34; &#34;break_glass&#34;</span> {
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">  name</span>                 <span class="o">=</span> <span class="s2">&#34;infra-break-glass&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">  assume_role_policy</span>   <span class="o">=</span> <span class="k">data</span><span class="p">.</span><span class="k">aws_iam_policy_document</span><span class="p">.</span><span class="k">break_glass_trust</span><span class="p">.</span><span class="k">json</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">  max_session_duration</span> <span class="o">=</span> <span class="m">3600</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">  tags</span> <span class="o">=</span><span class="n"> { Purpose</span> <span class="o">=</span> <span class="s2">&#34;emergency-escalation&#34;</span> }
</span></span><span class="line"><span class="ln">7</span><span class="cl">}</span></span></code></pre></div><p>如果團隊有 ChatOps 或 ticketing 系統，把 break-glass 的觸發綁進去可以增加一層人為確認：operator 在 Slack 或 ticket 裡申請提權、另一個人核可、系統開放 assume。這層確認的目的是在事後稽核時留下一條清楚的「誰授權了這次提權」紀錄，而非阻止操作本身。</p>
<h3 id="事後回顧">事後回顧</h3>
<p>每一次 break-glass 使用都應該進入事後回顧：為什麼需要提權？這個操作能不能改寫成 operator 層級的權限就能完成？如果某類操作反覆觸發 break-glass，代表 operator 的權限邊界需要調整——把那類操作從 admin 降到 operator，而不是讓 break-glass 變成常態。</p>
<p>回顧的輸出是權限邊界的校準，不是對操作者的檢討。</p>
<h2 id="定期-access-review">定期 access review</h2>
<p>權限分配不是一次性的設定。人會換組、離職、從 contractor 轉正職、從開發角色轉管理角色，每一次角色變動都可能讓既有的權限配置過期。定期 review 的責任是找出「權限比當前角色需要的更寬」的身分，把它們收斂回來。</p>
<h3 id="節奏與方法">節奏與方法</h3>
<p>每季做一次 access review 是多數團隊能維持的最小節奏。Review 的步驟：</p>
<ol>
<li>拉出所有 IAM user 和 role 的清單，標注每個身分目前的分級（admin / operator / viewer）</li>
<li>比對每個身分的實際角色——這個人現在還在做需要 operator 權限的工作嗎？</li>
<li>用 IAM Access Analyzer 檢查哪些權限在過去 90 天沒被使用過——沒用到的權限是收斂候選</li>
<li>特別檢查 break-glass 的使用紀錄——有沒有人的 break-glass 使用頻率高到代表他的基線權限該調整</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 產出 credential report，列出所有 user 的 key 建立時間與使用時間</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws iam generate-credential-report
</span></span><span class="line"><span class="ln">3</span><span class="cl">aws iam get-credential-report --output text --query Content <span class="p">|</span> base64 -d <span class="p">|</span> head -20
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># 查 Access Analyzer 的 finding（哪些權限可收斂）</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">aws accessanalyzer list-findings --analyzer-arn &lt;analyzer-arn&gt; <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>  --filter <span class="s1">&#39;{&#34;status&#34;: {&#34;eq&#34;: [&#34;ACTIVE&#34;]}}&#39;</span></span></span></code></pre></div><h3 id="管理層報告">管理層報告</h3>
<p>Access review 的結果適合用兩個數字向管理層報告：<strong>覆蓋率</strong>（已 review 的身分數 / 總身分數）與<strong>異常數</strong>（權限過寬或長期未使用的身分數）。異常數的趨勢比單次數字更有意義——持續上升代表新人 onboarding 時的權限配置流程有缺口，持續下降代表 review 在發揮作用。</p>
<p>導入時程參考：第一次 access review 約需半天到一天（盤點 + 比對 + 收斂），後續每季約需 2-4 小時。</p>
<h2 id="職務交接與離職處理">職務交接與離職處理</h2>
<p>一個人離開團隊時，他持有的所有存取路徑都需要被回收。手動建立的存取路徑越多，離職處理越容易遺漏。</p>
<h3 id="離職-checklist">離職 checklist</h3>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>操作</th>
          <th>驗證方式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>IAM user / SSO 帳號</td>
          <td>停用或刪除</td>
          <td>credential report 裡不再出現</td>
      </tr>
      <tr>
          <td>長期 access key</td>
          <td>撤銷所有 key</td>
          <td><code>list-access-keys</code> 回傳空</td>
      </tr>
      <tr>
          <td>個人 MFA 裝置</td>
          <td>解除綁定</td>
          <td><code>list-mfa-devices</code> 回傳空</td>
      </tr>
      <tr>
          <td>被加進的 IAM group</td>
          <td>移除成員</td>
          <td><code>get-group</code> 裡不再出現</td>
      </tr>
      <tr>
          <td>可 assume 的 role trust policy</td>
          <td>從 principal 清單移除</td>
          <td>trust policy 裡沒有該 user ARN</td>
      </tr>
      <tr>
          <td>第三方服務的 SSO 授權</td>
          <td>撤銷（GitHub org、CI 平台、Slack workspace 等）</td>
          <td>該帳號無法登入</td>
      </tr>
      <tr>
          <td>共用密碼 / shared credential</td>
          <td>輪替（如果存在的話）</td>
          <td>Secrets Manager 版本更新</td>
      </tr>
  </tbody>
</table>
<p>權限設計越集中在 role-based（用 IAM group 或 SSO permission set），離職處理越簡單——停用 SSO 帳號就自動切斷所有透過 SSO 取得的 role。反過來，如果有大量手動 attach 的 policy 或直接寫在 trust policy 裡的 user ARN，離職時要逐一找出並移除，容易遺漏。</p>
<p>離職後的 credential rotation 有一個常被忽略的風險：輪替範圍沒有按作用域分批。一個反例是多個服務共用同一把 secret，輪替時切新憑證的服務跟還只認舊憑證的服務之間出現認證窗口不一致，導致跨系統連鎖中斷。穩定的做法是先分域隔離受影響服務、恢復雙憑證窗口、再逐批收斂（見 <a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">反例：憑證輪替未分 Scope</a>）。</p>
<h3 id="交接的可執行性">交接的可執行性</h3>
<p>交接的成本取決於知識有多少沉澱在程式碼裡、有多少留在個人腦中。如果環境的建立方式是一份 IaC、變更方式是 PR 歷史，新接手的人讀 code 跟 PR 描述就能重建脈絡。如果關鍵操作（某台資料庫的特殊 parameter、某條 security group 規則的理由）只存在離職者的記憶裡，交接窗口一過就永久遺失。</p>
<p>可操作的檢驗：問「如果這個人下週離職，團隊能不能只靠讀 repo 就安全地操作他負責的環境？」答案是否定的部分，就是交接的優先補強項——優先把它們寫進 IaC 或 PR 描述，而不是寫進交接文件（交接文件會過期，IaC 跟著環境一起演進）。</p>
<p>這個議題在<a href="/blog/infra/09-driving-adoption/trust-alignment-knowledge-sharing/" data-link-title="怎麼把 infra 推動起來 — 信任赤字、期望值對齊與知識共享" data-link-desc="技術正確不等於推得動 — infra 在商業優先級裡吃虧的結構性原因，以及用可回退切片、期望值對齊與知識分散來跨過組織關卡">知識共享優於個人英雄主義</a>有組織層面的展開。</p>
<h2 id="contractor-與外部-vendor-存取">Contractor 與外部 vendor 存取</h2>
<p>外部人員（contractor、顧問、SaaS vendor 的技術支援）需要存取雲端環境時，原則是給最小範圍、設明確時限、留完整紀錄。</p>
<h3 id="範圍限制">範圍限制</h3>
<p>外部人員的 role 用 Permissions Boundary 設定權限天花板，確保即使有人誤 attach 了過寬的 policy，操作範圍也不超過 boundary 允許的上限。Scope 到具體的資源 ARN（某個 S3 bucket、某台 RDS instance），而非帳號級別的 wildcard。</p>
<p>如果團隊已經有<a href="/blog/infra/02-identity-credentials/multi-account-strategy/" data-link-title="跨帳號策略 — Organizations、SCP 與帳號工廠" data-link-desc="用 AWS Organizations 把環境拆成獨立帳號、用 SCP 設定連管理員都越不過的護欄、用帳號工廠讓每個新帳號自帶安全基線">跨帳號策略</a>，把外部人員的 workload 放在獨立帳號或 sandbox OU 裡，用 SCP 限制該帳號能操作的服務類型，是比 role 級別限制更強的隔離。</p>
<h3 id="時限控制">時限控制</h3>
<p>外部存取的 IAM user 或 SSO 帳號在建立時就設定到期日。多數雲端平台支援 session duration 限制（role 的 <code>max_session_duration</code>）和帳號層級的停用排程。合約結束日應該對應到存取到期日——這個對應關係寫進 IaC（用 tag 標注到期日）或團隊的 access review checklist，避免合約結束後存取仍然開著。</p>
<h3 id="稽核紀錄">稽核紀錄</h3>
<p>外部人員的操作需要比內部人員更嚴格的稽核。CloudTrail 預設記錄所有 API 呼叫，但 review 的頻率要提高——外部人員的操作紀錄每週抽查，而非等到季度 access review 才回頭看。查的是：有沒有存取超出約定範圍的資源？有沒有在非工作時間操作？有沒有大量的 read 操作指向敏感資料？</p>
<p>這些紀錄同時也是合約管理的依據——如果外部 vendor 的技術支援存取了超出約定範圍的資源，紀錄是釐清責任的事實基礎。</p>
<h2 id="跨分類引用">跨分類引用</h2>
<ul>
<li>→ <a href="/blog/infra/02-identity-credentials/iam-oidc-privilege-boundary/" data-link-title="身分與憑證地基 — IAM 模型、OIDC 短期憑證與權限邊界設計" data-link-desc="IAM 的 identity / policy / role 三元件、最小權限的持續收斂、用 OIDC 取代長期 access key，以及 SCP 與 Permissions Boundary 的環境隔離">身分與憑證地基</a>：IAM role / policy / OIDC 的技術機制</li>
<li>→ <a href="/blog/infra/02-identity-credentials/multi-account-strategy/" data-link-title="跨帳號策略 — Organizations、SCP 與帳號工廠" data-link-desc="用 AWS Organizations 把環境拆成獨立帳號、用 SCP 設定連管理員都越不過的護欄、用帳號工廠讓每個新帳號自帶安全基線">跨帳號策略</a>：用 OU 和 SCP 在帳號層級隔離外部人員</li>
<li>→ <a href="/blog/infra/08-governance-habits/tagging-secrets/" data-link-title="Tagging 規範與 Secrets 不進 code" data-link-desc="tag 讓資源可盤點、可清理、可歸屬；密鑰存在專用服務裡而非 code 或 state，兩者都屬於 day-1 就該立的治理地基">治理好習慣</a>：tagging 標注存取到期日、secrets 不進 code</li>
<li>→ <a href="/blog/infra/09-driving-adoption/trust-alignment-knowledge-sharing/" data-link-title="怎麼把 infra 推動起來 — 信任赤字、期望值對齊與知識共享" data-link-desc="技術正確不等於推得動 — infra 在商業優先級裡吃虧的結構性原因，以及用可回退切片、期望值對齊與知識分散來跨過組織關卡">怎麼把 infra 推動起來</a>：知識共享與交接的組織面</li>
</ul>
]]></content:encoded></item></channel></rss>