OpenAI 服務帳戶是隸屬於專案的非人員身分。Terraform 可以建立不含預設角色的帳戶、定義一組最小權限,並透過群組指派這組權限。請在 Terraform 之外,透過管理 API 建立及管理服務帳戶的 API 金鑰。
本指南依循典型的服務帳戶啟用工作流程:
- 建立不含預設專案角色或 API 金鑰的服務帳戶。
- 透過群組指派自訂專案角色,僅授予工作負載所需的權限。
- 建立限定權限範圍的 API 金鑰,並將其儲存至機密管理工具。
開始之前
完成 Terraform 供應器設定,將管理 API 金鑰匯出為環境變數 OPENAI_ADMIN_KEY,並將現有專案的 ID 匯出為環境變數 PROJECT_ID。
評估服務帳戶的建立、匯入、替換及刪除操作時,請使用測試組織。
建立不含預設角色的服務帳戶
使用 Terraform 建立服務帳戶:
resource "openai_project_service_account" "application" {
project_id = "proj_123"
name = "example-application-development-service-account"
}
output "service_account_id" {
value = openai_project_service_account.application.service_account_id
}
將 proj_123 替換為服務帳戶將隸屬的現有專案 ID。
供應器會建立服務帳戶身分,但不會產生 API 金鑰或指派預設專案角色。Terraform 會將服務帳戶 ID 及其他非敏感中繼資料儲存在狀態中。在此階段,服務帳戶尚無任何專案權限。
指派最小權限
定義自訂專案角色,僅納入工作負載所需的權限。建立群組、將服務帳戶加入群組,再將角色指派給該群組。此範例允許群組成員建立回應:
resource "openai_project_role" "application" {
project_id = openai_project_service_account.application.project_id
role_name = "Application response writer"
description = "Allows the application to create responses"
permissions = ["api.responses.write"]
}
resource "openai_group" "application_access" {
name = "example-application-development-access"
}
resource "openai_group_user" "application" {
group_id = openai_group.application_access.group_id
user_id = openai_project_service_account.application.id
}
resource "openai_project_group_role" "application_access" {
project_id = openai_project_service_account.application.project_id
group_id = openai_group.application_access.group_id
role_id = openai_project_role.application.role_id
}
openai_project_role 資源定義一組最小權限,openai_group_user 將服務帳戶加入群組,而 openai_project_group_role 則將角色指派給該群組。加入群組的每個服務帳戶都會繼承相同的專案角色。請將 api.responses.write 替換為工作負載獲准使用的最小權限集合。如需瞭解透過群組授予專案存取權的詳細資訊,請參閱專案與存取權。
審查並套用組態:
terraform plan
terraform apply
如果自訂專案角色已能提供工作負載所需的權限,
就不要指派內建的 member 或 owner 角色。請將存取權限制在
已核准的權限集合內。
建立限定權限範圍的 API 金鑰
套用 Terraform 組態後,透過建立專案服務帳戶 API 金鑰端點建立 API 金鑰。API 只會傳回一次金鑰的完整值,因此請在發出請求前保護回應檔案:
SERVICE_ACCOUNT_ID="$(terraform output -raw service_account_id)"
umask 077
curl -X POST \
"https://api.openai.com/v1/organization/projects/$PROJECT_ID/service_accounts/$SERVICE_ACCOUNT_ID/api_keys" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production App",
"scopes": ["api.responses.write"]
}' \
--output service-account-api-key.json
選擇能滿足工作負載需求的最小權限範圍。API 金鑰的權限範圍可以進一步限制服務帳戶的權限,但無法授予其所獲指派的專案角色以外的權限。
將 service-account-api-key.json 中的 value 傳遞給已核准的機密管理工作流程,且不要將其列印出來。機密管理工具儲存並驗證機密後,請刪除回應檔案:
rm service-account-api-key.json
只要 service-account-api-key.json 仍存在,就必須將其視為機密。不要提交此檔案、將金鑰寫入 Terraform 組態、透過 Terraform 輸出公開金鑰,或將其作為 Terraform 變數傳遞。
API 參考文件包含回應結構及各程式語言的範例。支援工作負載身分聯合的工作負載,可以使用相同的服務帳戶與最小權限角色,無需建立 API 金鑰。
匯入現有服務帳戶
由 Terraform 建立的服務帳戶不需要匯入。若要將在 Terraform 之外建立的服務帳戶納入管理,請使用相同的專案 ID 與名稱宣告該帳戶:
resource "openai_project_service_account" "application" {
project_id = "proj_123"
name = "example-application-development-service-account"
}
在執行一般套用操作之前,先匯入現有身分:
SERVICE_ACCOUNT_ID="<existing-service-account-id>"
terraform import \
openai_project_service_account.application \
"$PROJECT_ID/$SERVICE_ACCOUNT_ID"
terraform plan
匯入後的第一份執行計畫應不會提出任何服務帳戶變更。如果計畫提出替換帳戶,請先將組態中的名稱與專案調整為與現有帳戶一致,再套用計畫。
匯入不會復原或儲存 API 金鑰、不會變更服務帳戶現有的專案角色,也不會匯入其群組成員資格。如果要由 Terraform 管理現有的 openai_project_role、openai_group、openai_group_user 與 openai_project_group_role 資源,請宣告並匯入這些資源。工作負載會繼續從機密管理工具讀取現有機密。
套用資源宣告之前,請先匯入服務帳戶。如果先執行套用操作, Terraform 會建立另一個服務帳戶, 而不是將現有身分納入管理。
復原或輪替憑證
API 金鑰的完整值僅會出現在建立 API 金鑰的回應中。之後擷取專案 API 金鑰時,傳回的值會經過遮蔽,因此無法復原遺失的金鑰。
在不中斷工作負載的情況下,替換遺失或需要輪替的憑證:
- 將替代帳戶宣告為新的
openai_project_service_account資源,並使用與舊帳戶不同的 Terraform 資源名稱。 - 套用組態以建立替代服務帳戶。
- 使用
openai_group_user將替代帳戶加入現有群組,讓它繼承最小權限專案角色。 - 透過管理 API 為替代帳戶建立 API 金鑰,並使用已核准的機密管理工作流程儲存金鑰。
- 部署替代金鑰,並使用替代帳戶驗證工作負載。
- 從 Terraform 組態中移除舊的
openai_project_service_account及其openai_group_user資源。保留替代服務帳戶仍在使用的角色、群組與群組角色指派。 - 審查並套用刪除舊服務帳戶及其群組成員資格的執行計畫,接著執行
terraform plan,並確認結果顯示無需任何變更。
刪除 openai_project_service_account 資源會刪除遠端服務帳戶。務必明確要求審查這項變更,尤其是在舊憑證仍用於處理流量時。
如需更全面瞭解將資源納入狀態管理及移除資源的行為,請參閱匯入與調和。
執行完整範例
前述各項範例使用具體值,說明如何建立服務帳戶、指派角色及建立 API 金鑰。完整組態則以變數取代專案特定的值與權限,方便在不同環境中重複使用。
將下列組態儲存為 main.tf:
terraform {
required_version = ">= 1.0"
required_providers {
openai = {
source = "openai/openai"
version = ">= 1.0.0"
}
}
}
provider "openai" {}
variable "project_id" {
type = string
description = "ID of the existing OpenAI project."
}
variable "service_account_name" {
type = string
description = "Name of the application service account."
}
variable "project_role_permissions" {
type = list(string)
description = "Least-privilege project permissions for the application."
validation {
condition = length(var.project_role_permissions) > 0
error_message = "Provide at least one approved project permission."
}
}
resource "openai_project_service_account" "application" {
project_id = var.project_id
name = var.service_account_name
}
resource "openai_project_role" "application" {
project_id = var.project_id
role_name = "Application API access"
description = "Least-privilege permissions approved for the application"
permissions = var.project_role_permissions
}
resource "openai_group" "application_access" {
name = "${var.service_account_name}-access"
}
resource "openai_group_user" "application" {
group_id = openai_group.application_access.group_id
user_id = openai_project_service_account.application.id
}
resource "openai_project_group_role" "application_access" {
project_id = var.project_id
group_id = openai_group.application_access.group_id
role_id = openai_project_role.application.role_id
}
output "project_id" {
value = var.project_id
}
output "service_account_id" {
value = openai_project_service_account.application.service_account_id
}
output "group_id" {
value = openai_group.application_access.group_id
}
output "project_role_id" {
value = openai_project_role.application.role_id
}
建立 terraform.tfvars,填入現有專案 ID、不重複的服務帳戶名稱,以及已核准的最小專案權限集合:
project_id = "proj_123"
service_account_name = "example-application-development-service-account"
project_role_permissions = [
"api.responses.write",
]
初始化 Terraform,然後審查並套用已儲存的執行計畫:
terraform init
terraform fmt
terraform validate
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
第一份執行計畫應包含五項待新增的資源:服務帳戶、其自訂專案角色、群組、群組成員資格,以及群組角色指派。再次執行 terraform plan,確認組態不會再產生任何變更。
在 Terraform 之外建立服務帳戶 API 金鑰:
PROJECT_ID="$(terraform output -raw project_id)"
SERVICE_ACCOUNT_ID="$(terraform output -raw service_account_id)"
umask 077
curl -X POST \
"https://api.openai.com/v1/organization/projects/$PROJECT_ID/service_accounts/$SERVICE_ACCOUNT_ID/api_keys" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production App",
"scopes": ["api.responses.write"]
}' \
--output service-account-api-key.json
將傳回的 API 金鑰值移至已核准的機密管理工具,然後刪除 service-account-api-key.json。不要將金鑰儲存在 Terraform 組態、狀態或輸出中。