雲直充 雲直充 立即諮詢

GCP帳號充值 GCP 數據庫權限不足導致無法寫入修復

谷歌雲GCP / 2026-07-18 14:24:12

第一章:先把問題定義清楚

「權限不足導致無法寫入修復」聽起來像一句泛泛的錯誤描述,但在 GCP 的世界裡,這句話背後通常藏著幾個關鍵差異:你到底在寫哪個資源、由誰來寫、透過什麼路徑寫、以及資料寫入時還牽涉到哪些附帶服務。只要有一個環節對不上,就會從表面上的“無法寫入”變成真正的“查不到原因、怎麼加權限都不對”。

因此第一步永遠不是急著加權限,而是把問題框進可判斷的範圍。你需要記下:錯誤訊息原文(包含 service name、permission、resource name)、發生在什麼服務或介面(例如 Cloud Run、GKE、App Engine、本地服務、CI/CD),以及寫入動作是什麼(INSERT/UPDATE/寫文件/寫入表資料/寫入快取)。如果你能取得錯誤報文中帶出的 permission(例如 cloudsql.instances.updatedatastore.entities.createbigquery.tables.updateDatafirestore.databases.documents.create 之類),修復會快很多。

接著,確認目標資料庫類型。GCP 的資料庫很多:Cloud SQL(MySQL/PostgreSQL/SQL Server)、Firestore、Cloud Datastore、BigQuery、Spanner、甚至是 Cloud Storage 也常被誤當成“數據庫”。不同產品的權限模型不同,錯誤碼也不同。你如果把 Firestore 的建議套到 BigQuery,最後只會得到一串“加了權限仍不通”的挫折感。

第二章:常見錯誤的幾種真相

在排查過程中,我最常見到的狀況其實很固定。它們看似不同,根因卻重複出現:

2.1 寫入帳號不是你以為的那個

很多團隊以為自己是用某個服務帳號(service account)在跑,例如 Cloud Run 的 default service account 或你在程式裡指定的憑證。但實際上,Cloud Run/ GKE/ Workload Identity 的繫結方式可能讓程式用到“另一個身份”。於是你在 IAM 上對 A 帳號加了資料庫寫入權限,結果程式其實用的是 B 帳號,當然還是寫不進去。

最可靠的做法是:回頭看日誌(Cloud Logging)中針對錯誤請求那一筆,是否能看到“Principal / serviceAccount / actor”。若沒有,就要查應用的憑證載入方式、服務的 service account 設定、Workload Identity 交換規則、以及 CI/CD 部署後是否改過服務帳號。

2.2 權限加了,但作用範圍不對

即使你加對了服務帳號,也常遇到“作用範圍不對”的問題。IAM 綁定的是資源層級(project、dataset、table、firestore database、cloud sql instance 等)。你給了某個層級的權限,但寫入目標在另一個層級或不同資源上。

典型例子:你給了 BigQuery dataset 的 roles/bigquery.dataEditor,卻寫入的是另一個 dataset;或你給 Firestore 的整個 project 權限,但你的程式其實連到不同的 database ID(例如 default vs 非 default)。

2.3 需要的不是“寫入”,而是“寫入 + 附帶服務”

資料庫寫入有時會牽涉加密、暫存、索引維護或事件觸發。若你在 Cloud SQL 啟用了 CMEK(Customer-Managed Encryption Key),那麼除了資料庫寫入權限,你還需要對 KMS key 有使用權。當 KMS 權限不足時,錯誤有時不會直接說“KMS 權限不足”,而是表面呈現成寫入失敗或某種 generic 的 permission error。

同樣地,Firestore 有時牽涉到事件匯出(Export)、或觸發 Cloud Functions/Workflows。你以為你只是在寫文件,結果程式寫完後還需要另一個服務去讀或寫,這就會把權限問題“延伸”到另一個身份。

第三章:用錯誤訊息做路標,而不是用猜的

GCP 的權限錯誤通常都不會完全沒線索。關鍵是你要把訊息拆開來讀。即便你不是 IAM 專家,也能從錯誤中找到至少三個元素:

  • 缺少的 permission 或角色(role)片段
  • 目標 resource(在哪個 instance、哪個 dataset、哪個 table、哪個 collection/database)
  • 執行的主體(service account / user / identity pool)

有了這三個元素,你就能判斷:問題是“身份不對”、還是“資源不對”、或是“角色不完整”。

3.1 先查日誌:找到正確的一筆 request

日誌不是用來“看心情”的。你要鎖定同一次請求、同一次錯誤、同一個錯誤層級。建議你從以下來源開始:應用的 stderr/stdout、服務的 request log、以及 GCP 的 error log。當錯誤發生在 Cloud Run 或 GKE,log 裡通常能看見 request-id 或 trace-id。你拿到 trace-id 後,能更快在相關服務中找到同一條鏈路。

很多團隊的誤區是“只看摘要”。摘要可能只告訴你“permission denied”,但不告訴你缺哪個 permission、不告訴你是哪個資源。你要找帶有完整 error details 的那一段。

3.2 把缺少的 permission 映射回 IAM 角色

當你看到具體 permission(例如 spanner.databaseUser 不是 permission 但角色名,或直接顯示 method permission),你可以用它來縮小候選角色。這一步的重點不是“完全記住所有角色”,而是把角色範圍判斷出來:它到底是資料層(data.*)、還是管理層(instances.*、datasets.*)、或是加密層(cloudkms.*)。

舉例來說:如果你是 BigQuery 寫入資料,一般不會只靠 roles/bigquery.jobUser;你需要能真正修改資料的權限(例如 bigquery.tables.updateData 或對應角色)。如果你只加了 jobUser,程式可以發起查詢或 load job,但在寫入 stage 失敗時仍會報權限不足。

第四章:分情境修復策略(Cloud SQL / Firestore / BigQuery 為主)

下面我用“你通常遇到什麼狀況、要怎麼驗證身份、需要補什麼權限”來講。你不必照抄每個角色名,但要理解它們對應的能力層級。

4.1 Cloud SQL:連上了但 INSERT 失敗

Cloud SQL 的權限分兩層:GCP 層的 IAM 與資料庫本身的 DB 權限(user/role)。你說“權限不足”,通常會發生在以下兩種之一:

  • 應用的服務帳號沒有權限連到 instance(IAM 或網路策略)
  • 服務帳號連到後,用來登入資料庫的 DB 帳號沒有 INSERT/UPDATE 權限

修復順序我建議這樣走:

  1. 先確認 Cloud SQL instance 的 IAM:檢查目標 instance 上是否授予正確服務帳號所需角色(常見如 roles/cloudsql.client)。
  2. 確認你是否使用了正確的連線方式(Unix socket/SSL/TCP)以及 Cloud SQL Auth Proxy 是否有使用對應憑證。
  3. 登入資料庫後檢查 DB 角色:例如 MySQL 的 GRANT、PostgreSQL 的權限與 schema 設定。

很多“加 IAM 仍不行”的案例,實際上是 DB 層沒有權限。反之亦然:DB 帳號有 INSERT 但沒有 cloudsql.instances.connect 之類能力,則連線都不會成功,更不可能寫入。

還有一種容易忽略:如果你用的是 CMEK 或某些加密/備份功能,需要對 KMS key 或其他相關資源授權。此時錯誤往往和你預期的 “INSERT” 不完全一致,但本質仍是權限不足。

4.2 Firestore / Datastore:寫文件被拒絕

Firestore 常見的情境是:程式能讀,但不能寫;或者寫某個 collection 失敗。這裡要注意三個控制點:

  • IAM 角色(project 層級或 database 層級)
  • Firestore 規則(如果使用 Security Rules,它會在資料層做拒絕)
  • 身份(service account vs user 身份 vs token)

如果你是後端服務(Cloud Run/GKE)透過 Admin SDK 或直接服務端寫入,通常不會走 client side rules 的邏輯,但仍可能因為 IAM 缺少 firestore.databases.documents.create 或相關角色而被拒絕。

GCP帳號充值 修復步驟:

  1. 先確認寫入請求使用的身份是誰。若你是用 Admin SDK,確認你用的憑證是否是預期的 service account。
  2. 檢查該 identity 是否具備 documents create/update 权限。常見的做法是授予對應角色(例如 roles/datastore.user 或 Firestore 等價角色),但要以錯誤訊息的 permission 為準。
  3. 若你也有使用 Firestore Security Rules(例如前端直連),則還要檢查 rules 是否允許該身份在目標 path 上的寫入。

4.3 BigQuery:能發 job 但 load 或 insert 失敗

GCP帳號充值 BigQuery 的權限常見“看起來差不多,實際差很多”。你可能已經能跑查詢 job(因為 jobUser 權限足夠),但寫入(load、insert、updateData)缺乏資料層權限,導致 job 在執行 stage 報 permission denied。

這類問題我通常建議你鎖定三件事:

  • 你是要把資料寫到哪個 dataset/table?
  • load job 的資料來源(例如 GCS)是否也需要讀或寫權限?
  • 你的主體是否只有 jobUser,但缺少對 table 的 updateData 或對 dataset 的 dataEditor 類權限?

修復步驟:

  1. 確認呼叫端的 service account。
  2. 在 dataset 層或 table 層授予對應資料寫入權限(以錯誤訊息顯示的 permission 為準)。
  3. 若 load/append 依賴 GCS,確保 service account 同時具備對儲存桶的讀權限(例如 Storage Object Viewer)或對應 KMS 使用權限。

另外,很多團隊會遇到“寫入失敗但錯誤訊息指向的是 tables.updateData 或 jobs.create”。這並不矛盾:要麼你沒權跑 job,要麼你跑了 job 但 job 裡的寫入動作不允許。把兩者分清楚,你就知道要補哪一段。

GCP帳號充值 4.4 服務帳號沒掛上去:Workload Identity 與憑證交換

GCP帳號充值 當你用 GKE Workload Identity 或其他身份聯邦(例如 Workload Identity Pool),最常發生的是“身份看似正確,但實際 Principal 不對”。常見原因包括:attribute mapping 不匹配、Kubernetes service account 和 GCP service account 的綁定未生效、或部署到另一個 namespace 後沒有設定。

這種情況下,最好的排查方式通常是回到“錯誤訊息中的 principal”。你會在拒絕訊息看到主體名稱。你只要把主體名稱和你以為的 service account 對上,就能很快判斷是“綁定沒生效”還是“權限沒授予”。

第五章:制定一份可落地的修復清單

很多文章給的是理論,我們要的是能在今天把問題解掉的清單。下面這份清單你可以當作 SOP,用於未來任何“無法寫入”的權限錯誤。

5.1 收集資訊(先不改任何設定)

  • 錯誤原文(包含 permission、resource、status code)
  • 寫入流程所在服務(Cloud Run/GKE/函數/本地程式/批次 job)
  • 呼叫端身份(service account / user / principal)
  • 目標資源(instance、database、dataset、table、collection path)

5.2 驗證身份(確認“到底誰在寫”)

  • 查看服務的 service account 設定(Cloud Run、GKE、App Engine)
  • 若使用 Workload Identity,核對 Kubernetes SA ↔ GCP SA 的綁定與 namespace
  • 在日誌中比對 principal 名稱是否和你要授權的帳號一致

5.3 最小權限授予(先補“缺的那一段”)

  • 根據缺少 permission 對應資料層/管理層權限
  • 授權範圍要對齊資源層級(project/dataset/table 或 instance)
  • 避免“一次性給 admin”,除非只是短期排錯且有回收計畫

5.4 檢查附帶權限(KMS、GCS、觸發器)

  • 若有 CMEK,檢查 KMS key 的 roles(通常需要能使用加密/解密的權限)
  • GCP帳號充值 BigQuery load/導入常需要 GCS 讀取權限
  • 寫入後若觸發其他服務,需補上“鏈路延伸”的身份權限

5.5 重新測試與回收

  • 重新部署或重新觸發同一條寫入流程
  • 確認錯誤消失後,把過度授權的臨時權限移除
  • 把修復原因寫進運維筆記:為什麼會缺、缺在哪個 resource、誰的身份

GCP帳號充值 第六章:避免重演的工程做法

權限問題之所以反覆出現,不是因為人不細心,而是因為系統缺少“可預期性”。你可以用工程化方式降低不確定性。

6.1 讓憑證可觀測:把 principal 記錄在應用日誌

很多服務在寫入失敗時只記錄了錯誤堆疊,但沒有記錄執行身份。你可以在應用啟動時把服務帳號或憑證來源標出(例如從環境變數或身份資訊取得)。等之後再遇到權限不足,你不需要猜“是不是用錯帳號”,而是直接看到。

注意:不要在日誌中輸出敏感憑證內容;記錄身份名稱即可。

6.2 基礎設施即程式:讓 IAM 變更能被審查

若你的 IAM 設定散落在手動操作,未來一定會“有人加過但忘了加在哪”。把 IAM 設定納入版本管理(例如用 IaC),讓變更可以被 code review,並且能追溯“為什麼今天這個 service 寫不進去”。

GCP帳號充值 特別是多環境(dev/stage/prod)時,最容易出錯的是:你在 prod 加了權限,結果服務跑在 stage。

6.3 預先做權限壓測:用測試身份驗證寫入路徑

把“寫入測試”當作單元/整合測試的一部分。每次部署後,使用同一個身份去寫一筆測試資料,確保 permission 與規則都通過。這比等到正式業務流程跑起來才發現 permission denied 要省很多時間。

第七章:把修復講成結論,讓你下次更快

當你再次遇到「GCP 數據庫權限不足導致無法寫入」時,可以用一句話當作心法:

先確認“誰在寫”與“寫到哪裡”,再對照錯誤訊息中缺的 permission,在正確資源層級補上最小權限,同時檢查 KMS/GCS 等附帶依賴。

很多人把時間浪費在“加權限—仍然失敗—再加更多權限”。這不會收斂,因為你沒有把缺的那個環節釘住。你只要拿到錯誤訊息中的 principal 與 resource,就能把範圍縮到幾個可能性,修復自然會越來越快。

7.1 一個典型修復範例(概念版)

假設你的 Cloud Run 寫入 Cloud SQL 時收到 permission denied。你做了三步:

  • 在日誌裡看到拒絕主體是某個 service account A,而你以為是另一個 service account B。
  • 你在 Cloud SQL instance 上針對 A 補了 client 連線權限。
  • 接著登入資料庫確認 DB user 沒有 INSERT 權限,於是補上 schema/table 的 GRANT。

最後寫入恢復正常。你看起來改了兩處地方,但本質是同一件事:身份與權限在兩個層級都要對齊。

結語:真正的修復是理解權限模型

權限不足的錯誤很常見,但它不應該讓你一直停在猜測。GCP 的權限模型核心其實就幾件事:身份(principal)、資源(resource)、能力(permission/role)、以及附帶依賴(KMS、GCS、規則與觸發)。你每次都用這個框架去拆解,就算換了資料庫產品或換了部署方式,排查效率也會越來越高。

下一次你再看到“無法寫入”,不要先想“要給哪些 admin 權限”。先想:錯誤訊息告訴我誰、寫在哪裡、缺哪種能力?把這三個答案找到,你的修復就會變成可驗證的行動,而不是運氣。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系