列為「風險最高」的那把金鑰,我們決定晚點再撤
上一次鑑識就點名它,但它擁有一萬多個檔案、七個以上的線上服務靠它活著,所以排在「先搬消費者再停用」。一個月後,它在五個小時內替別人跑了 6,350 萬 input token,整個專案被 Google 停權。
- 8/27 部署平台環境變數外洩,裡面有一把掛著專案 Owner 的雲端金鑰。9/15 的鑑識已經把它列為「風險最高、仍有效」,但因為很多服務靠它,決定晚點再撤。
- 10/14 晚上 10 點到隔天凌晨 3 點,有人拿這把金鑰狂打 Google 的 AI 模型服務:5,000 多次呼叫、6,350 萬個輸入 token。隔天整個專案被 Google 停權,所有依賴它的服務一起停擺。
- 能證明的是哪一把金鑰、打了什麼、打了多少;不能證明的是攻擊者是誰、薪資試算表有沒有被讀過,因為那一層記錄從來沒開。
一張排在待辦第四位的票
10 月 15 日早上,信箱裡躺著一封 Google 的通知:專案「與符合盜用特徵的濫用活動有關聯」,已被暫停,原因疑似服務帳戶憑證或 API 金鑰外洩。接著就是熟悉的連鎖反應,所有讀寫試算表的排程、兩支 AWS Lambda、自動化流程平台上的幾條工作流,同時開始報錯。
這次沒有什麼好猜的。被打的那把金鑰我們早就認識:它是一個用來讀寫 Google Sheets/Drive 的 GCP:Service Account,身上掛著 roles/owner,金鑰檔建於 2024 年 7 月、從來沒有換過。8 月 27 日部署平台出事時它就在外洩範圍內;9 月 15 日那次鑑識,報告裡已經用粗體寫著它「風險最高、仍有效」。當時的決定是:它擁有一萬一千多個 Drive 檔案、七個以上的線上服務靠它運作,先把消費者一個一個搬走,再停用它。
於是它在待辦清單上排了一個月。10 月 14 日台灣時間晚上 10 點到隔天凌晨 3 點,有人拿它去呼叫 Vertex AI,五個小時之後專案就被停權了。這篇要講的不是攻擊者有多厲害,他其實沒做什麼新鮮事;要講的是**「已知高風險,但因為依賴太多而延後撤銷」這個決定,到底在跟誰賭時間。**時間一律為台灣時間(UTC+8),技術數字另標 UTC。
一把鑰匙,住在三種地方
這個專案原本很單純:沒有虛擬機,Compute Engine API 甚至沒啟用,平常只有排程透過服務帳戶讀寫試算表、上傳檔案到 Drive。問題在那個服務帳戶本身。它是很多年前為了「方便」建的,權限直接給了專案 Owner;後來大家發現它好用,就把同一份金鑰 JSON 複製到每一個需要碰試算表的地方。
到事件當下,這把金鑰同時住在三種地方。部署平台上,多個服務把整段 JSON 塞在環境變數裡,名稱各自取,有 GOOGLE_AuthKey、GDRIVE_CREDENTIALS_JSON、GOOGLE_SERVICE_ACCOUNT_JSON;12 個 GitHub repo 把 key 檔 commit 進去(全部是 private);開發者本機則掃出 42 份複本。它在 Drive 上看得到的範圍,包含薪資與財報試算表。
原本已有的防護幾乎是零:沒有預算警示、沒有 Data Access 稽核記錄、沒有依憑證分組的用量監控,業務用不到的 Vertex AI API 也沒有被關掉。下表是這把憑證的完整樣貌。
| 服務 | 憑證類型 | 用途 | 存在形式 | 放在哪 | 權限範圍 | 狀態 |
|---|---|---|---|---|---|---|
| GCP:Service Account(IAM 服務帳戶) | Google Service KEY JSON | 排程與後台讀寫 Google Sheets、上傳與讀取 Drive 檔案 | JSON 檔,內含 private_key 的 PEM 區塊;在部署平台上是整段 JSON 字串塞進環境變數 | 部署平台多個服務的環境變數(三種變數名)+ 12 個私有 GitHub repo 內的 key 檔 + 開發者本機 42 份複本 | roles/owner(專案最高權限);Drive 上擁有 11,190 個檔案,可見範圍含薪資、財報試算表 | 2024-07 建立、從未輪替;8/27 平台外洩範圍內;9/15 鑑識列為最高風險但未撤銷;10/14 被盜用;10/15 刪除,該帳戶使用者金鑰歸零 |
| 部署平台上其他同批外洩的憑證 | 多種(另一把 Google Service KEY JSON、資料庫密碼、AWS access key 等) | 各自不同 | 明文環境變數 | 部署平台 | 各自不同 | 大多已於 8 月底輪替;另一把 GCP 金鑰 8/28 就被 Crusader 殭屍網路使用,詳見前案 |
一把鑰匙放在三種地方,代表撤銷它的那一刻,三種地方的所有消費者都會同時斷線。這正是它被延後的理由,也是它最後被打的理由。
從外洩到停權,48 天
這條時間線要看的不是 10/14 那五個小時,而是前面那段「已知、但還沒動」的空白。
- 2024-07建立這把 Google Service KEY JSON,之後從未輪替服務帳戶金鑰的 validAfterTime。
- 2026-08-27部署平台環境變數外洩,這把金鑰在範圍內平台通知;三個服務的環境變數含同一把金鑰的 private_key_id。
- 2026-08-28同批外洩中的另一把 GCP 金鑰,隔天就被 Crusader 殭屍網路拿去開 VM、打 Vertex AI前案的 Cloud Audit Logs 與帳單。
- 2026-09-15鑑識報告把這把金鑰列為「風險最高、仍有效」,決定先搬消費者再停用當時的鑑識摘要與待辦。依賴盤點:11,190 個 Drive 檔案、7 個以上線上服務。
- 2026-10-14 22:00攻擊者開始呼叫 Vertex AI:先在 9 個區域試模型,大量 404Cloud Monitoring:serviceruntime 請求數,credential_id 等於該服務帳戶的 uniqueId。
- 2026-10-14 22:49Google 自動建立 aiplatform service agent(首次呼叫 Vertex 的副作用,不是攻擊者改權限)Admin Activity:principal 是 service-agent-manager 的 SetIamPolicy。
- 2026-10-14 23:00改為集中打 europe-west1,成功 5,178 次Cloud Monitoring 依區域與回應碼分組。
- 2026-10-15 02:59最後一筆呼叫,之後專案被停權Cloud Monitoring 時序在 18:59 UTC 之後歸零;Google 通知信。
- 2026-10-15刪除金鑰、停用 aiplatform API、提出申訴、開始把消費者搬到無金鑰代理處置紀錄;keys list 回傳 0 把使用者金鑰。
- 待補攻擊者的來源 IP、資料是否被讀Data Access 稽核沒開,停權期間 logging API 也被擋。
最該記住的是 9/15 到 10/14 這 29 天。外洩後的第 19 天我們就知道它危險,攻擊者在第 48 天才動手,中間每一天,撤銷都還來得及。
他做的事很少,但每一步都很熟練
到這裡,其實已經足夠理解整起事件。如果你關心的是管理與制度問題,可以直接往〈往下追四層,最後一層是我們自己的決定〉繼續閱讀。如果你想知道我們怎麼在專案被停權的狀態下,還能從 Cloud Monitoring 還原這五個小時,下面開始進入技術鑑識。
先記住一件事就好:攻擊者從頭到尾沒有開任何機器,也沒有動任何權限。他只是拿著一把現成的 Owner 金鑰,把 AI 模型服務當成自己的額度在用。
這七格裡有三格標成缺口,但它們是「真的沒發生」:持久化與提權有完整的 Admin Activity 可以作證,C2 則根本不需要。真正「不知道有沒有發生」的是另一件事——這個帳戶看得到的薪資與財報試算表,有沒有被讀過;那一層從來沒有記錄,下面的證據會講。
停權中的專案,Monitoring 還讀得到
專案被停權之後,直接查 Cloud Logging 會回 CONSUMER_SUSPENDED,連 Monitoring API 也一樣被擋。但 Monitoring 的時序資料其實還在,擋住你的是「用誰的配額查」。只要換一個正常的專案當 quota project,就讀得到。
深入閱讀怎麼在停權狀態下讀 Monitoring 時序gcloud 用 --billing-project,REST 帶 x-goog-user-project
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "x-goog-user-project: OTHER_HEALTHY_PROJECT" \ "https://monitoring.googleapis.com/v3/projects/SUSPENDED_PROJECT/timeSeries?\ filter=metric.type%3D%22serviceruntime.googleapis.com%2Fapi%2Frequest_count%22%20AND%20resource.labels.service%3D%22aiplatform.googleapis.com%22\ &interval.startTime=2026-10-14T00:00:00Z&interval.endTime=2026-10-15T06:00:00Z\ &aggregation.alignmentPeriod=3600s&aggregation.perSeriesAligner=ALIGN_SUM" # 每條時序的 metric.labels 會帶 credential_id、method、response_code, # resource.labels 帶 location。依 credential_id 分組,就知道是哪一個身分在打。
gcloud 指令則加 --billing-project=OTHER_HEALTHY_PROJECT。這招對 Logging 無效:停權期間 Logging API 仍回 CONSUMER_SUSPENDED,所以 Admin Activity 是停權前另外匯出的。
靠這個方法拿到的數字,足以把「是哪一把」「打了什麼」「打了多少」三件事釘死,下面五條是可證明的。
能證明的到此為止。接下來兩條是推論,三條是缺口。
五條證明、兩條推論、三個缺口。釘死的都是雲端自己會記的東西,缺的都是我們自己沒打開的東西。
往下追四層,最後一層是我們自己的決定
接下來從技術回到管理與制度。你不需要記住上面每一個模型名稱,只要記住一件事:這把金鑰在被打之前一個月,就已經被我們自己點名過了。
表面上的原因很直接:一把外洩的 Owner 金鑰沒有撤銷,被人拿去打 Vertex AI。再往下一層是技術,三件事同時成立:一個只需要讀寫試算表的帳戶掛著 roles/owner,所以它叫得動整個專案的任何 API;專案根本用不到的 aiplatform API 處於可用狀態,所以它有東西可以叫;長期金鑰沒有到期日,2024 年建的鑰匙 2026 年照樣能換 token。三件事少一件,這五個小時就不會長這樣。
往上追到管理,問題就清楚了:9/15 那次鑑識不是沒發現,是發現了、評估了、然後選擇延後。延後的理由是真的:一萬多個 Drive 檔案歸它所有,刪帳戶會連檔案一起消失;七個以上的服務在用它,一撤銷就全部停擺。但這個決定有一個隱藏的前提——「攻擊者會等我們搬完」——而這個前提沒有人寫下來,也沒有人能保證。決策紀錄裡有「先搬再停」,卻沒有截止日、沒有「搬遷期間要加的監控」、也沒有「如果被打怎麼辦」。
最後一層是制度,這一層我只能寫成推測:同一把金鑰被複製到環境變數、12 個 repo、42 份本機檔案,輪替它的成本高到讓每個人都本能地想往後排。換句話說,延後撤銷不是某一個人的判斷失誤,是整個架構讓「立刻撤銷」變成一件太貴的事。第三層是這一次的原因,第四層是下一次的原因。
我們看見了,只是沒有一個會響的東西
這次和前案最大的不同是:風險不是沒被看見,是被看見了、寫進報告了、排進待辦了,然後安靜地放了一個月。
真正缺的是「它被用了會有人知道」這件事。如果有預算警示,10/14 晚上 11 點帳單曲線一翹就會有人收到信;如果有依 credential_id 分組的用量警示,一個只讀寫試算表的身分突然開始呼叫 aiplatform,第一個 404 尖峰就該響;如果 aiplatform API 一開始就是關的,九個區域的探測會全部撞在 403 上,連訊號都不需要。一個已知外洩、決定延後處理的憑證,最少該配一條專屬的監控,這次一條都沒有。
所以這次的「偵測」,又是 Google 的停權通知替我們做的,時間是攻擊結束後的隔天早上。
10/15 那一天:先斷鑰匙,再談搬家
停權通知到的當天,第一個動作是刪掉這個服務帳戶唯一的一把使用者金鑰,刪完再列一次,回傳 0 把。這件事一個月前就能做,今天做反而沒有成本:專案已經停權,服務帳戶本來就不能用,刪掉不會多造成任何中斷。這句話本身就是這篇最痛的一句。
接著停用專案的 aiplatform API,這個專案從來不需要 Vertex AI。然後才開始鑑識:借另一個專案當 quota project 讀出 Monitoring 時序,確認 credential_id、區域、模型與 token 量;檢查 Admin Activity,確認沒有新金鑰、沒有 IAM 異動、那筆 SetIamPolicy 是 service agent;實測正式站路徑、清點 repo 與本機複本,排除公開外洩的路線。鑑識結果整理好之後,依 Google 通知中的流程提出申訴。
復原走兩條路並行。能改成無金鑰的就改:讀寫 Sheets/Drive 的服務改打一個跑在 Cloud Run 上的代理,代理用自己的 runtime 服務帳戶呼叫 Google API,呼叫端只拿一個可撤銷的 token,能碰哪些試算表由白名單決定,手上沒有任何私鑰。一時改不了程式的,就各自發一個新的服務帳戶,只分享它真正需要的檔案、不給任何專案層角色,一個服務一把,出事只撤那一把。
這次做對的,大多在事後;做錯的,只有一件
先講做對的部分。9/15 那次鑑識的判斷本身是準的,它點名的正是後來被打的那一把;10/15 的處置也很乾淨:先撤銷、再停 API、再鑑識,順序沒有錯,而且靠 quota project 的技巧,在停權狀態下還是把「哪一把、打什麼、打多少」三件事證明出來,也用 Admin Activity 排除了後門帳號的疑慮。
該改的其實只有一件,但它決定了整件事:我們把「撤銷」排在「搬遷」之後。正確的順序應該反過來——先開一條新路讓服務有地方走,哪怕只是臨時的新金鑰,然後當天就斷掉舊鑰匙,搬遷再慢慢做。我們選了「零停機」,結果拿到的是「全部停機,而且時間由別人決定」。另外兩個小錯是放大器:延後撤銷的那段期間沒有配任何監控,決策也沒有寫截止日,於是「暫時」就自然變成了「一直」。
之後我們改了什麼
當天做完的有三件:刪除這把金鑰、停用 aiplatform API、提出申訴並把鑑識結果附上。同時把仍在使用這個身分的服務列成清單,逐一改走無金鑰代理或獨立的新服務帳戶,自動化流程平台裡用到它的憑證、兩支 Lambda、repo 內的 key 檔都在清單上。
一個月內要做的是把「延後撤銷」這個選項本身改掉。外洩事件的處置規則加一條:高權限憑證一旦確認在外洩範圍內,撤銷不得晚於 24 小時;如果真的必須延後,就要寫下截止日、負責人,並在延後期間配一條專屬的用量警示與預算警示。所有專案先開 Data Access 稽核(至少 Drive、Sheets 與 Vertex AI)與預算警示,業務用不到的 API 一律關掉。
這一季以後的目標,是讓輪替便宜到沒有人想拖:資料用服務帳戶一律不給專案層角色,靠檔案分享取得權限;機密只存在 Secret Manager 一個地方,環境變數只放引用;應用程式透過無金鑰代理或 Workload Identity 拿短期憑證;用組織政策 iam.disableServiceAccountKeyCreation 擋住新金鑰的產生。一把金鑰散在幾十個地方,就會有人覺得「明天再換」;只存在一個地方,換它就是一個指令。
下面這張成本表要先講清楚:帳單還沒出,所以可證明的金額是零。這不代表沒有損失,而是我們不把估算寫成收據。
| 項目 | 用量 | 單價 | 期間 | US$ | NT$ | 舉證 |
|---|---|---|---|---|---|---|
| Vertex AI:Pro 級模型(gemini-4-argon、gemini-3.1-pro-preview) 估:模型等級與單價皆為推定,gemini-4-argon 未必是 Pro 級牌價 | input 4,421 萬、output 624 萬 token | 估 US$2/百萬 input;US$12/百萬 output | 10/14 五小時 | 163.30 | 5,226 | token 數取自 Cloud Monitoring(可證);單價為同級公開牌價推估 |
| Vertex AI:Flash 級模型(gemini-3.8-flash 等 5 個) 估:含 3.8/3.7/3.6/3.5-flash 與 3-flash-preview,扣除已列模型後的餘量 | input 約 1,439 萬、output 約 252 萬 token | 估 US$0.50/百萬 input;US$3/百萬 output | 10/14 五小時 | 14.76 | 472 | token 數取自 Cloud Monitoring;單價推估 |
| Vertex AI:Flash-Lite 級(gemini-3.5-flash-lite) 估 | input 490 萬、output 44 萬 token | 估 US$0.10/百萬 input;US$0.40/百萬 output | 10/14 五小時 | 0.67 | 21 | token 數取自 Cloud Monitoring;單價推估 |
| Vertex AI:圖片模型(gemini-3-pro-image、nano-banana-2.1) Monitoring 有 token 計數但沒有輸出張數,無法換算 | 張數不明 | 依張數計價 | 10/14 | — | — | 缺帳單 SKU 明細 |
| RawPredict 試打 Claude on Vertex 推論是在試 Claude;成功與否、用了多少 token 都不明 | 120 次 | 依模型 token 計價 | 10/14 | — | — | Monitoring 只有請求數,缺回應碼以外的明細 |
| 實際帳單 寫作時尚未出帳,且專案停權中;出帳後以帳單取代上面三列推估 | Vertex AI 全部 SKU | 帳單實付 | 10/14 | — | — | 待 GCP 帳單報表 |
| 停權造成的服務中斷 營業影響無法量化;這是延後撤銷真正想避免、卻反而全額付出的成本 | 所有依賴此專案的排程、Lambda、自動化工作流與後台 | — | 10/15 起至搬遷完成 | — | — | 無營收或 SLA 紀錄可對應 |
| 處置與搬遷人力 估:動作有紀錄,工時與日費為估算 | 撤銷、鑑識、申訴、消費者搬到無金鑰代理,約 1.5 人日 | 顧問日費 NT$27,500(估) | 10/15 起 | 1289.06 | 41,250 | 處置紀錄可證動作;工時為估算 |
| 攻擊者的成本 估:他用我們的專案,換到價值上百美元的 AI 額度 | 一份撿來的金鑰、一支腳本、五小時 | 邊際成本趨近 0 | 10/14 | 0.00 | 0 | 沒有開機器、沒有改權限,可證他除了腳本之外沒有其他投入;實際支出無從得知 |
| 合計(僅可證明列) | 0.00 | 0 | ||||
推估下來,Vertex 本身大約是 US$180 等級,比前案還高一點,但真正的帳在那一列無法量化的「全部停機」。延後撤銷是為了避免停機,最後付出的正是停機,而且付的時間點不是我們選的。
帶得走的五件事
從攻擊者的角度看,這是一筆很好做的生意。他手上有一批 48 天前撿到的環境變數,裡面每一把金鑰都可能已經失效,所以他不急,一把一把慢慢試。這一把還活著,而且是 Owner、而且專案的 Vertex AI 沒關、而且沒有人在看帳單。他花五個小時探測區域、試模型、把最貴的模型用到撞牆為止,然後換下一把。他不知道、也不需要知道,這把金鑰在我們的待辦清單上已經排了一個月。
- 01「已知高風險但先不撤」不是中性的決定,是在賭攻擊者會等你搬完;這次賭輸的代價,正是當初想避免的全面停機。
- 02撤銷和搬遷的順序要反過來:先開一條臨時的新路,當天斷舊鑰匙,搬遷再慢慢做。
- 03只讀寫試算表的服務帳戶不該是 roles/owner;權限夠小,就算漏撤一把,攻擊者也叫不動 Vertex AI。
- 04用不到的 API 要關,Data Access 稽核與預算警示要先開;事後才想開的東西,這次都只能寫成缺口。
- 05一把金鑰散在環境變數、12 個 repo 與 42 份複本,輪替成本就高到讓人拖延;把它設計成只存在一個地方,撤銷才會是一個指令。
如果只想記十個詞,就記下面這十個;順序是照「讀完最該帶走」排的。
- 01延後撤銷(deferred revocation)這篇的主角。沒有截止日、沒有專屬監控的「先不撤」,實際上就是「等別人替你決定什麼時候撤」。
- 02roles/owner一個只寫試算表的帳戶掛著它,外洩時丟掉的就是整個專案,連用不到的 Vertex AI 都能被叫動。
- 03credential_idCloud Monitoring 依它分組,就能在沒有 Data Access 稽核的情況下證明是哪一把金鑰在打。
- 04quota project(x-goog-user-project)專案被停權後還能讀 Monitoring 的關鍵:換一個正常的專案出配額。
- 05Data Access 稽核記錄沒開它,攻擊者 IP 與「薪資表有沒有被讀」都永遠是缺口。它必須在事件之前打開。
- 06CONSUMER_SUSPENDED停權後 Logging API 回的錯誤。看到它就知道,事前沒匯出的記錄這時已經拿不到了。
- 07aiplatform.googleapis.com業務用不到就該停用。這次如果它是關的,九個區域的探測會全部撞在 403 上。
- 08RawPredictVertex AI 上呼叫第三方模型(如 Claude)的方法;出現在不該用 AI 的專案裡,就是有人在試額度。
- 09預算警示(Budget alerts)成本最低的偵測。這次是 Google 停權信替我們做了偵測,時間已經是隔天早上。
- 10無金鑰代理/Workload Identity讓應用程式手上沒有私鑰,輪替就從「改幾十個地方」變成「撤一個 token」,人就不會想拖。
如果回到 9 月 15 日那一天
假設回到 9 月 15 日,報告上那行「風險最高、仍有效」剛寫完,我會這樣用掉接下來的一小時。
前十五分鐘不碰任何程式,只做兩件事:把這個服務帳戶的 roles/owner 拿掉,改成只靠檔案分享取得權限;把專案的 aiplatform API 停用。這兩步不會讓任何讀寫試算表的服務斷線,卻讓這把金鑰就算外洩,也叫不動 Vertex AI。
第二個十五分鐘建一把臨時的新金鑰,只給最關鍵的兩三個服務換上,其他服務接受短暫停機;換好之後立刻刪除舊金鑰,用舊憑證打一次 API,看到 invalid_grant 才算完成。停機的時間是我們選的,通知也是我們自己發的。
剩下的半小時用來補監控與寫下決策:開 Data Access 稽核與預算警示,替這把還沒撤的金鑰配一條專屬用量警示,取名 alert-deferred-sa-d7q,再把「延後項目」的截止日與負責人寫進待辦。一小時之後才輪到真正的慢工:消費者逐一搬到無金鑰代理、清掉 12 個 repo 與本機的複本、把那一萬多個 Drive 檔案的擁有權轉出去。那時候慢慢做就好,因為舊鑰匙已經不在了。
這一小時,今天就可以先在自己的專案上預演一次。下面五步全部唯讀,十五分鐘內做得完。
全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。
- 列出專案裡掛著 Owner 的服務帳戶。
gcloud projects get-iam-policy PROJECT_ID \ --flatten='bindings[].members' \ --filter='bindings.role:roles/owner AND bindings.members:serviceAccount' \ --format='value(bindings.members)'看到什麼代表什麼:有任何一個只負責讀寫試算表或檔案的帳戶出現在這裡,就是本案的形狀:外洩一把,丟掉整個專案。 - 對上一步找到的帳戶,列出使用者建立的金鑰與建立日期。
gcloud iam service-accounts keys list \ --iam-account=SA_EMAIL --managed-by=user \ --format='table(name.basename(), validAfterTime)'看到什麼代表什麼:建立日期超過一年,或出現在任何一次外洩通知的範圍內卻還在,就是一張正在倒數的待辦。 - 確認業務用不到的 AI 服務是不是開著。
gcloud services list --enabled --project=PROJECT_ID \ --filter='config.name:(aiplatform.googleapis.com OR generativelanguage.googleapis.com)'看到什麼代表什麼:有回傳、但你的業務從沒用過 AI 模型,就代表外洩的金鑰可以直接拿你的專案跑 AI。 - 檢查有沒有開 Data Access 稽核記錄。
gcloud projects get-iam-policy PROJECT_ID --format='yaml(auditConfigs)'看到什麼代表什麼:輸出是空的,代表出事時你不會有攻擊者 IP,也無法證明機敏檔案沒被讀。 - 看這個專案有沒有預算警示。
gcloud billing projects describe PROJECT_ID --format='value(billingAccountName)' gcloud billing budgets list --billing-account=BILLING_ACCOUNT_ID --format='table(displayName, amount)'看到什麼代表什麼:沒有任何預算涵蓋這個專案,代表下一次的偵測又會是雲端商的停權通知。
每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。
延伸閱讀
教學版:四道防線只要做到一道,這 15 天就不會發生
同一起事件的教學版:15 天逐分鐘攤開,每一步標出為什麼會成功、哪一道控制擋得下來。不發金鑰、不給 Owner、關掉沒用的 API、預算警示,四道都沒有。
排程回報「找不到帳戶」,被停權的是整個專案
一支只負責把資料寫進試算表的小程式,用的帳號卻是整個雲端專案權限最大的角色。金鑰六年沒換、外流後被用了 15 天:帳單 US$146,但「資料有沒有被看過」我們永遠答不出來。
我們寫了一道關卡防自己,第二次部署它就亮了紅燈
沒有攻擊、沒有外洩、沒有帳單,這是一份設定稽核紀錄:一支只該讀寫試算表的 GCP:Service Account,在專案層是 Owner。拿掉只要一行,拿掉前要先查什麼?