OpenAI 서비스 계정은 프로젝트가 소유하며 워크로드가 인증에 사용하는 비사용자 계정입니다. Terraform으로 기본 역할이 없는 계정을 만들고, 필요한 최소 권한을 하나의 역할로 정의한 다음 그룹을 통해 할당할 수 있습니다. 서비스 계정의 API 키는 Terraform 외부에서 Administration 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 키의 권한 범위를 설정하면 서비스 계정의 권한을 더 제한할 수 있지만, 할당된 프로젝트 역할에 없는 권한을 부여할 수는 없습니다.
value 필드의 값을 service-account-api-key.json에서 읽어 출력하지 않고 승인된 비밀 관리 워크플로우에 전달하세요. 비밀 관리 도구에서 키를 저장하고 검증한 다음 응답 파일을 삭제하세요.
rm service-account-api-key.json
service-account-api-key.json은 삭제할 때까지 비밀 정보로 취급하세요. 파일을 커밋하거나 키를 Terraform 구성에 기록하지 마세요. 키를 Terraform 출력으로 노출하거나 Terraform 변수로 전달해서도 안 됩니다.
API 레퍼런스에서 응답 구조와 언어별 예제를 확인할 수 있습니다. 워크로드 ID 페더레이션을 지원하는 워크로드는 API 키를 만들지 않고도 같은 서비스 계정과 최소 권한 역할을 사용할 수 있습니다.
기존 서비스 계정 가져오기
Terraform으로 만든 서비스 계정은 가져올 필요가 없습니다. 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 키를 조회하면 일부가 가려진 값이 반환되므로 분실한 키는 복구할 수 없습니다.
자격 증명을 분실했거나 교체할 때가 되었다면 다음 절차에 따라 워크로드 중단 없이 교체하세요.
- 대체 계정을 새
openai_project_service_account리소스로 선언하세요. Terraform 리소스 이름은 기존 계정과 다르게 지정하세요. - 구성을 적용해 대체 서비스 계정을 만드세요.
- 대체 계정이 최소 권한 프로젝트 역할을 상속하도록
openai_group_user로 기존 그룹에 추가하세요. - Administration API로 대체 계정의 API 키를 만들고 승인된 비밀 관리 워크플로우를 통해 저장하세요.
- 새 키를 배포하고 워크로드가 대체 계정으로 정상 작동하는지 확인하세요.
- Terraform 구성에서 기존
openai_project_service_account리소스와 해당 계정의openai_group_user리소스를 제거하세요. 대체 서비스 계정이 계속 사용하는 역할, 그룹, 그룹 역할 할당은 유지하세요. - 기존 서비스 계정과 해당 그룹 멤버십을 삭제하는 실행 계획을 검토하고 적용하세요. 그런 다음
terraform plan을 실행해 변경 사항이 없는지 반드시 확인하세요.
openai_project_service_account 리소스를 삭제하면 원격 서비스 계정도 삭제됩니다. 이 삭제 작업에는 명시적인 검토를 요구하세요. 기존 자격 증명으로 아직 요청을 처리하고 있다면 특히 중요합니다.
기존 리소스를 Terraform 상태에 포함하거나 상태에서 제거할 때의 동작에 관한 자세한 내용은 가져오기 및 상태 조정을 참고하세요.
전체 예제 실행하기
앞의 예제에서는 구체적인 값을 사용해 서비스 계정 생성, 역할 할당, 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 구성, 상태 또는 출력에 저장하지 마세요.