【Explanation】GCP Security — 使用 IAM condition 實現 BeyondCorp 安全模型

Kellen
15 min readOct 8, 2023

--

IAM 應該大家都不陌生,像是可以使用 IAM 來控制誰有權存取我們專案中的內容以及誰可以對儲存桶等內容執行哪些操作,但如果我們想限制某人何時可以執行某些操作或對儲存桶中的哪些物件執行操作,該怎麼辦?這就是 IAM Condition 發揮作用的地方。

IAM condition 是什麼?

IAM condition 是 Google Cloud 中的一個功能,讓您可以根據特定情況,對資源的訪問權限進行更精細的控制。這表示我們可以選擇性的授予訪問權限,只有當特定條件得到滿足時,才提供這個資源給使用者。

例如,可以設置一個條件,僅在緊急情況下才允許某人訪問資源,或者僅當他們在公司辦公室時才允許訪問。每個條件都是一組規則,用來確定應該檢查哪些特定情況。如果條件成立,系統將僅在為 true 時才授予訪問許可。

IAM 條件是用「CEL」的通用表達式語言編寫的一個或多個規則。在允許與其關聯的已定義存取角色之前,每條規則都必須評估為 true。這些規則可以指定我們想要控制的資源類型、時間、日期和一些字串操作。

CEL 條件又是什麼?

CEL(Common Expression Language)是一種輕量級表達式語言,廣泛用於 Google Cloud Identity and Access Management(IAM)中的策略評估。簡單想像就是一個 IAM condition 語法,作用就像一個 SQL 語法,只允許通過符合特定規則的請求,用途是在對 IAM 進行約束和評估,而不是通用的複雜運算程式語言。

IAM conition 策略也可以綁定到資源和請求屬性的條件,例如:

  • 限時訪問;例如:僅允許在工作時間訪問
  • 訪問部分資源;例如:僅向前綴為「webapp-frontend-」的虛擬機器授予存取權限
  • 網路位址空間;例如:只允許從公司網路存取

簡單例子如下,真的很簡單:

resource.type == "compute.googleapis.com/Instance"

且 CEL 他的範圍很廣,可以使用不同的資源類型進行更多的過濾和控制,但也不是全部 GCP 服務都支援,畢竟 2020 年才剛推出來,需要對照一下官方文檔比較清楚,例如,以下是一些不同的Google Cloud資源類型示例:

  1. Cloud Storage Bucket:要選擇Google Cloud Storage Bucket,使用 resource.type == "storage.googleapis.com/Bucket"
  2. BigQuery Dataset:如果您想對 BigQuery 數據集應用特定的許可權或約束,使用 resource.type == "bigquery.googleapis.com/Dataset"
  3. Cloud SQL Instance:如果您想針對Cloud SQL實例應用特定的許可權,使用 resource.type == "sqladmin.googleapis.com/Instance"
https://cloud.google.com/iam/docs/conditions-overview

每種資源類型都具有獨特的識別符,它用於在 IAM 政策、資源過濾和其他Google Cloud 操作中區分不同類型的資源。您可以根據您的需求在表達式中使用不同的資源類型,以實現精確的資源控制和許可權分配。这些資源類型的詳細資訊通常可以在對應服務自己的 Google Cloud 文檔中可以找到。

提供更多場景的用法範例

案例一:限制訪問特定時間段和特定日期之間的訪問,例如生成一個不準成員還在下班時間處理公事的規則(良心企業)

CEL 會自動解析成條件建構的 UI 工具

可以結合使用時roles/compute.admin,將限制使用者和/或群組僅在辦公時間(週一至週五上午 9 點至下午 5 點)被授予該角色。

request.time.getHours("Asia/Taipei") >= 9 &&
request.time.getHours("Asia/Taipei") <= 17 &&
// Days of the week range from 0 to 6, where 0 == Sunday and 6 == Saturday.
request.time.getDayOfWeek("Asia/Taipei") >= 1 &&
request.time.getDayOfWeek("Asia/Taipei") <= 5

// 其實是從早上 9:00 ~ 下午 17:59:59 或是多加 getMinutes

這個就可以與 IAP 互相搭配,使用基於時間的 IAM 條件,這個條件允許使用者指定僅在特定時間範圍內授予許可權,或是對於第三方的廠商、顧問僅需要暫時進來查看使用。

案例二:IAM 給予 Storage 所有者或編輯者等權限將會存取所有 Google Cloud Storage (GCS) 儲存桶。因此,我希望允許某些人僅存取特定的 GCS 儲存桶或甚至是特定位置

resource.type == "storage.googleapis.com/Bucket" &&
resource.name.startsWith("projects/_/buckets/inputbucket-001/objects/example-folder")

一般從 IAM 給予某個主體(Principle) roles/storage.objectCreator後,加上 condition,將限制使用者和/或群組只能在限定的儲存桶中建立新inputbucket-001物件example-folder,若是隨意上傳到儲存桶的根目錄或任何其他根級別資料夾將被拒絕。

寫法上以 projects/_ 後面接 buckets 指定 Bucket,然後在接續 objects 指定資料夾(概念上)。請留意,Cloud Storage 儲存桶中的「資料夾」本質上是一個對象,它只是概念上的「資料夾」

我們來拆解上述 CEL 的語法

  • resource.name.startsWith「資源」是桶中的目標物件,name.startsWith告訴 API 我們的目標是物件名稱的前綴。
  • projects/_/buckets/inputbucket-001提供inputbucket-001的儲存桶予 Google Storage API 屬性
  • objects/example-folder屬性引用告訴 API,我們正在定位名稱以example-folder為前綴的任何物件

瞧!您現在已將您的帳戶限制為僅對名為 example-folder 的資料夾具有儲存物件建立者權限。

若是傳錯位置,異常訊息會提醒你
AccessDeniedException: 403 xxx@project-id.iam.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket.

一樣有其他方法能達成,討論作法與比較

GCS 桶的存取限制時,也可以在 GCS 桶側邊 ≡ 新增權限,雖然這種方法很簡單,但是很難理解哪些使用者和服務帳戶被允許存取哪些機 GCS 儲存桶。因此,這次我們使用 IAM Conditions 功能來控制對 GCS 儲存桶的存取,好處是可以在管理報表或是排障上都只要在 IAM 即可處理,不過在組織內部要採行那種方法,也是要先談定好!

(📅 20231102 新增) 實作指引參考
【How-to Guides】GCP 踩坑日常 — 如何操控 IAM conditin 細化 prefix 不同權限

案例三:團隊成員有 Data Analyst , Data Engineering, Data Scientist,有些表格為 infra 本身的系統日誌,我希望限制 Data Scientist 可以對 Big Query 上面的系統表有讀取權限!

此範例為資料集中的表格授予 cloudysanfrancisco@gmail.com BigQuery Data Viewer 角色。透過此角色,使用者可以查詢表並透過 bq 工具存取它。使用者無法在 Google Cloud 控制台中查看該表,因為他們沒有 資料集的權限。table_1dataset_1bigquery.tables.list

{
"members": [cloudysanfrancisco@gmail.com],
"role": roles/bigquery.dataViewer,
"condition": {
"title": "Table dataset_1.table_1",
"description": "Allowed to read table with name table_1 in dataset_1 dataset",
"expression":
resource.name == projects/project_1/datasets/dataset_1/tables/table_1
&& resource.type == bigquery.googleapis.com/Table
}
}

限制

請勿為資料集、表格、排程和模型(目前文件只看到支援這四種類型)以外的 BigQuery 資源新增條件

案例四:使用 IAM condition 畫分出開發環境與營運環境權限

一個名為 DEV 小組是管理公司的 infra 的團隊,有時需配合 IT 部長兼任開發工作,而 DEV 被部長允許可以創建與刪除 Compute Engines,並在組織層級定義了一個 IAM 允許策略,部長將 DEV 群組與 Compute Admin 角色綁定。這一切都很順利、運作得很好。直到,最近很受行長推崇的明星開發成員(半澤)在部長的指示下刪除了 Compute Engines(好死不死刪到公司最重要的服務),因在高度監管行業內,陸續有檢調與內部稽核單位進來查證。

這要怎麼千倍奉還

這個背景故事突顯了在 Google Cloud 中管理權限和存取控制的挑戰,有時,為了方便可能忽略了管理和權責畫分原則,特別是在需要區分開發環境和生產環境權限時,這樣的疏忽可能導致重大問題。

接續試著用 IAM condition 來把此次事件處理一下,並將 PROD的環境分開來,確保只有另一個 SRE 單位才能刪除營運環境的 Compute Engine,除可以防止被挖洞事件再次發生,也算是在 Google Cloud 中實現權限和存取控制的重要工具。

動手作

我們搭配使用 Tags 目的是讓 Compute Engine 可以上 Tags,先來設定 key/value 畫面
keys 資訊查看
values 資訊查看

請注意為鍵和值生成的資訊,之後很快就會需要這些。我們將標籤(Tags)新增到要指定的 Compute Engine,這個機台是屬於營運環境(一般開發團隊是不能動手刪除),待會就來使用這些 Tags 應用在 IAM condition 上。

將標籤(Tags)新增到要指定的 Compute Engine

接續,因原本半澤的 IT 單位就已經使用了 IAP 機制,這邊我們更新角色 IAP-secured Tunnel User(舉例,不一定只能這個角色) IAM condition 策略,或是比較好的方式是設定在 Compute Engine Admin 這個的角色上面。

選擇 IAP 進入,並點選你要限制的 Compute Engine
IAP-secured Tunnel User 角色旁的 IAM 條件下點選編輯條件,並鍵入 CEL 語法
# CEL示例參考
!resource.matchTagId('tagKeys/281477069619531','tagValues/281479229836111')

該表達式以 “!” 開頭,表示資源標記為營運環境時,該位角色會被此條件限制住。

以上,快速用比較簡單的方式進行設定,把營運環境或特殊目的的設備限制權限。不過,個人覺得比較好的管理方式,可以考慮用資料夾來分類會更容易理解,將 Tags 標籤新增到名為的資料夾中prod,而該資料夾即是營運資源的根目錄,讓項下的資源可以繼承,例如以下:

Neil Kolban — Preventing prod access with IAM Conditions sample

以上案例探討了如何使用 IAM condition 的策略的概念,以實現更細粒度的權限管理,其他使用方式還在文檔上看到了有 IP 範圍、地理位置等用法,也可以套用在居家或遠端辦公的場景下

  • 基於IP範圍的 IAM 條件:這個條件允許您限制來自特定IP範圍的訪問
{
"title": "Only from trusted IP range",
"description": "Restrict access to a trusted IP range",
"expression": "ip_in_range(request.ip, '192.168.1.0/24')"
}
  • 基於地理位置的 IAM 條件:這個條件允許您限制來自特定地理位置的訪問
{
"title": "Only from the United States",
"description": "Restrict access to the United States",
"expression": "request.location.country_code == 'US'"
}

使用 IAM 條件有限制嗎?

發現還是有一些,不確定是不是 2020 第一季才推出

  • 目前只使用某些服務,並不是全部服務都可以使用,請查看此處的文件以了解有支援的服務
  • 它們不能與基本角色一起使用,allUsersallAuthenticatedUsers
  • 一個條件式中最多有 12 個邏輯運算符
  • 同一角色、同一成員最多可以有 20 個角色綁定
  • 最多有 100 個條件角色綁定

此外,有條件的角色綁定不會覆蓋無條件的角色綁定。如果使用者和/或群組綁定到沒有條件的角色,則該成員始終具有該角色。將成員新增至相同角色的條件綁定中不會產生任何效果。

例如我們對 開發者 創建了一個無條件綁定,這個無條件綁定的權限適用於所有成員;同時,我們創建了一個條件式綁定,其中條件是只有當成員位於特定 IP 範圍時才能具有 管理員 角色的權限

考慮以下情況:

  • 如果某位成員在特定 IP 範圍內,那麼他將同時擁有 開發者 角色和 管理員 角色的權限。換句話說,無條件綁定對該成員的權限仍然有效,而且更具優先順序。
  • 如果某位成員在特定 IP 範圍外,那麼他只能擁有 開發者 角色的權限,因為條件式綁定不再適用於他,無條件的綁定具有更高的優先順序。

這也並非問題點,只是在初期設定或設計角色權限時要留意,避免作業漏掉這塊而已。

可以透過 terraform 來應用嗎?

是的!這是直接來自 terraform 文件的範例:

resource "google_project_iam_member" "project" {
project = "your-project-id"
role = "roles/firebase.admin"
member = "user:jane@example.com"
condition {
title = "expires_after_2019_12_31"
description = "Expiring at midnight of 2019-12-31"
expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
}
}

--

--

Kellen

Backend(Python)/K8s and Container eco-system/Technical&Product Manager/host Developer Experience/早期投入資料創新與 ETL 工作,近期研究 GCP/Azure/AWS 相關的解決方案的 implementation