# 怎麼確認真的是唯讀？

{% embed url="<https://youtu.be/EBCDzgTQp2Y>" %}

我們把授權內容用**透明**的方式呈現：您可以在加入前的「唯讀角色」頁面直接看到 CloudFormation 建立的角色權限內容。

### 1. 身份驗證 - 這個角色「只允許被誰使用」？

請檢查 JSON 中的 CrossAccountRole 區段：

* `Principal: {"AWS": {"Ref": "EliteIamRole"}}`\
  \&#xNAN;**→ 含義：**&#x4EE3;表「只有勤英科技指定的 IAM Role（EliteIamRole）可以來扮演（Assume）這個角色」。其他人（就算知道 Role ARN）都不能直接使用。
* `Action: "sts:AssumeRole"`\
  \&#xNAN;**→ 含義：**&#x4EE3;表「只允許透過 AssumeRole 取得暫時性憑證」，不會建立/發放永久金鑰（Access Key）。
* `Condition: sts:ExternalId == EliteExternalID`\
  \&#xNAN;**→ 含義：**&#x9019;是 External ID 防護。防止第三方冒用、或混淆代理人問題（Confused Deputy Problem）。\
  即使有人知道 Role ARN，也不能隨便 Assume，必須帶正確 External ID 才能通過。

<mark style="color:$primary;">**這個 Role 不是誰都能使用，且有 External ID 保護。**</mark>

***

### 2. 權限驗證 - 這個角色「能做什麼？不能做什麼？」

我們的權限設定分為兩層，您可以逐一審查：

#### 第一層：AWS Managed Policy：`ReadOnlyAccess`, `SecurityAudit`

* `ManagedPolicyArns": ["arn:aws:iam::aws:policy/ReadOnlyAccess","arn:aws:iam::aws:policy/SecurityAudit"]`

我們使用「 AWS 官方的 ReadOnlyAccess 與 SecurityAudit」，這代表角色權限以「讀取/列出/描述」為主，此權限可以檢查您的設定與資源狀態，用於成本優化/資安/合規快篩，且不包含 「Start/Stop/Modify/Delete」 這類寫入變更行為。

#### 第二層：**Inline Policy：**`ExplicitDenySensitiveAccess`

雖然我們已經使用 ReadOnlyAccess 與 SecurityAudit，但為確保您的資料安全，我們加了第二層防護：「<mark style="color:red;">**禁止**</mark> Role 取得以下重要服務的權限」。

* `"Effect": "Deny"`：<mark style="color:red;">**代表禁止以下功能**</mark>
* `"lambda:GetFunction"`：取得 Lambda 函數的設定與程式碼位置
* `"lambda:GetFunctionCodeSigningConfig"`：取得 Lambda 程式碼簽章設定資訊
* `"s3:GetObject"`：下載 S3 物件內容
* `"s3:GetObjectVersion"`：下載指定版本的 S3 物件
* `"s3:GetObjectTorrent"`：以 BitTorrent 方式下載 S3 物件
* `"secretsmanager:GetSecretValue"`：讀取 Secrets Manager 中的內容
* `"secretsmanager:BatchGetSecretValue"`：批次讀取多個Secrets Manager中的內容
* `"ssm:GetParameter"`：讀取單一 Parameter Store 參數
* `"ssm:GetParameters"`：讀取多個 Parameter Store 參數
* `"ssm:GetParametersByPath"`：依路徑批次讀取參數
* `"ssm:StartSession"`：透過 Session Manager 建立遠端連線
* `"ssm:ResumeSession"`：恢復既有的 Session Manager 連線
* `"ssm:SendCommand"`：透過 SSM 對主機下遠端指令
* `"ssm:GetCommandInvocation"`：查看指令執行結果
* `"ssm:ListCommandInvocations"`：列出指令執行紀錄
* `"ssm:TerminateSession"：`終止 Session Manager 連線
* `"kms:Decrypt"`：使用 KMS 金鑰解密資料
* `"logs:GetLogEvents"`：讀取 CloudWatch Logs 日誌內容
* `"logs:FilterLogEvents"`：依條件搜尋日誌內容
* `"logs:StartQuery"`：啟動 Logs Insights 查詢
* `"logs:GetQueryResults"`：取得查詢結果
* `"logs:StopQuery"`：停止日誌查詢
* `"ecr:GetDownloadUrlForLayer"`：取得 ECR 映像層下載網址
* `"ecr:BatchGetImage"`：批次取得容器映像
* `"sqs:ReceiveMessage"`：從 SQS 佇列接收訊息
* `"sqs:DeleteMessage"`：刪除佇列中的訊息
* `"sqs:ChangeMessageVisibility"`：修改訊息隱藏時間
* `"codecommit:GitPull"`：從 CodeCommit 下載程式碼（git pull）
* `"codecommit:GetBlob"`：取得儲存庫中的 blob 內容
* `"codecommit:GetFile"`：取得單一檔案內容
* `"codecommit:GetFolder"`：取得資料夾內容
* `"codecommit:GetDifferences"`：取得程式碼差異
* `"cloudformation:GetTemplate"`：下載 CloudFormation 範本
* `"rds:DownloadDBLogFilePortion"`：下載部分 RDS 資料庫日誌
* `"rds:DownloadCompleteDBLogFile"`：下載完整 RDS 資料庫日誌&#x20;

<mark style="color:$primary;">**限制這些較容易暴露敏感資訊的權限**</mark><mark style="color:$primary;">**。**</mark>

```
 "Policies": [
          {
            "PolicyName": "ExplicitDenySensitiveAccess",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Deny",
                  "Action": [
                    "lambda:GetFunction",
                    "lambda:GetFunctionCodeSigningConfig",
                    "s3:GetObject",
                    "s3:GetObjectVersion",
                    "s3:GetObjectTorrent",
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:BatchGetSecretValue",
                    "ssm:GetParameter",
                    "ssm:GetParameters",
                    "ssm:GetParametersByPath",
                    "ssm:StartSession",
                    "ssm:ResumeSession",
                    "ssm:SendCommand",
                    "ssm:GetCommandInvocation",
                    "ssm:ListCommandInvocations",
                    "ssm:TerminateSession",
                    "kms:Decrypt",
                    "logs:GetLogEvents",
                    "logs:FilterLogEvents",
                    "logs:StartQuery",
                    "logs:GetQueryResults",
                    "logs:StopQuery",
                    "ecr:GetDownloadUrlForLayer",
                    "ecr:BatchGetImage",
                    "sqs:ReceiveMessage",
                    "sqs:DeleteMessage",
                    "sqs:ChangeMessageVisibility", 
                    "codecommit:GitPull",
                    "codecommit:GetBlob",
                    "codecommit:GetFile",
                    "codecommit:GetFolder",
                    "codecommit:GetDifferences",
                    "cloudformation:GetTemplate",
                    "rds:DownloadDBLogFilePortion",
                    "rds:DownloadCompleteDBLogFile"
                  ],
                  "Resource": "*"
                }
              ]
            }
          }
        ]
```

***

### 3. 為什麼一定要用 CloudFormation 建 Stack？

CloudFormation 的優點是「可稽核、可追溯、可撤銷」：

* 結構固定： 權限結構固定，不靠人工手動點來點去，大幅降低配置錯誤風險。
* 變更記錄： 任何修改都有 AWS 官方的變更記錄 (Log)。
* 一鍵撤銷： 若未來要停止服務，只需直接刪除該 Stack，就能把授權整包移除。
