Una cuenta de servicio de OpenAI es una identidad no humana que pertenece a un proyecto. Terraform puede crear la cuenta sin un rol predeterminado, definir un conjunto mínimo de permisos y asignarlo mediante un grupo. Usa la API de administración para crear y administrar las claves de API de la cuenta de servicio fuera de Terraform.
Esta guía sigue los pasos habituales para dar de alta una cuenta de servicio:
- Crea una cuenta de servicio sin rol de proyecto predeterminado ni clave de API.
- Asigna un rol de proyecto personalizado mediante un grupo para otorgar solo los permisos que necesita la carga de trabajo.
- Crea una clave de API con alcance limitado y guárdala en tu gestor de secretos.
Antes de empezar
Completa la configuración del proveedor de Terraform, exporta una clave de API de administrador como OPENAI_ADMIN_KEY y exporta el ID del proyecto existente como PROJECT_ID.
Usa una organización de prueba para evaluar la creación, importación, sustitución y eliminación de cuentas de servicio.
Crear una cuenta de servicio sin un rol predeterminado
Crea la cuenta de servicio con 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
}
Reemplaza proj_123 por el ID del proyecto existente al que pertenecerá la cuenta de servicio.
El proveedor crea la identidad de la cuenta de servicio sin generar una clave de API ni asignar un rol de proyecto predeterminado. Terraform guarda el ID de la cuenta de servicio y otros metadatos no sensibles en el estado. En este punto, la cuenta de servicio aún no tiene permisos en el proyecto.
Asignar los permisos mínimos necesarios
Define un rol de proyecto personalizado que incluya solo los permisos que requiere la carga de trabajo. Crea un grupo, agrega la cuenta de servicio a ese grupo y asigna el rol al grupo. En este ejemplo, los miembros del grupo pueden crear respuestas:
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
}
El recurso openai_project_role define el conjunto mínimo de permisos, openai_group_user agrega la cuenta de servicio al grupo y openai_project_group_role asigna el rol a ese grupo. Cada cuenta de servicio que se agrega al grupo hereda el mismo rol de proyecto. Reemplaza api.responses.write por el conjunto mínimo de permisos aprobados para tu carga de trabajo. Consulta Proyectos y acceso para obtener más información sobre el acceso a proyectos mediante grupos.
Revisa y aplica la configuración:
terraform plan
terraform apply
No asignes los roles integrados member ni owner si un rol de proyecto personalizado
otorga los permisos que necesita tu carga de trabajo. Limita el acceso al
conjunto de permisos aprobados.
Crear una clave de API con alcance limitado
Después de aplicar la configuración de Terraform, crea una clave de API mediante el punto de acceso Crear una clave de API para una cuenta de servicio del proyecto. La API devuelve el valor completo de la clave una sola vez, así que protege el archivo de respuesta antes de enviar la solicitud:
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
Elige los alcances más restringidos que permitan ejecutar la carga de trabajo. Los alcances de la clave de API pueden restringir aún más los permisos de la cuenta de servicio, pero no pueden otorgar permisos que excedan los del rol de proyecto asignado.
Pasa el contenido del campo value de service-account-api-key.json al flujo de trabajo aprobado para tu gestor de secretos sin imprimirlo. Una vez que el gestor de secretos haya guardado y verificado el secreto, elimina el archivo de respuesta:
rm service-account-api-key.json
Trata service-account-api-key.json como un secreto mientras exista. No incluyas el archivo en un commit, no escribas la clave en la configuración de Terraform, no la expongas en una salida de Terraform ni la pases como variable de Terraform.
La referencia de la API incluye la estructura de la respuesta y ejemplos para distintos lenguajes. Las cargas de trabajo que admiten la federación de identidades de cargas de trabajo pueden usar la misma cuenta de servicio y el mismo rol con privilegios mínimos sin crear una clave de API.
Importar una cuenta de servicio existente
No necesitas importar una cuenta de servicio creada por Terraform. Para administrar con Terraform una cuenta de servicio creada fuera de Terraform, declárala con el mismo ID de proyecto y el mismo nombre:
resource "openai_project_service_account" "application" {
project_id = "proj_123"
name = "example-application-development-service-account"
}
Importa la identidad existente antes de aplicar la configuración de la forma habitual:
SERVICE_ACCOUNT_ID="<existing-service-account-id>"
terraform import \
openai_project_service_account.application \
"$PROJECT_ID/$SERVICE_ACCOUNT_ID"
terraform plan
El primer plan después de la importación no debería proponer cambios en la cuenta de servicio. Si propone reemplazarla, ajusta el nombre y el proyecto en la configuración para que coincidan con los de la cuenta existente antes de aplicar el plan.
La importación no recupera ni guarda ninguna clave de API, no cambia el rol de proyecto actual de la cuenta de servicio ni importa su pertenencia al grupo. Declara e importa los recursos existentes openai_project_role, openai_group, openai_group_user y openai_project_group_role si quieres administrarlos con Terraform. La carga de trabajo seguirá leyendo los secretos existentes desde tu gestor de secretos.
Importa la cuenta de servicio antes de aplicar la declaración del recurso. Si aplicas primero la declaración, Terraform creará otra cuenta de servicio en lugar de adoptar la identidad existente.
Recuperar o rotar credenciales
El valor completo de la clave de API solo está disponible en la respuesta a la solicitud de creación de la clave. Si luego consultas la clave de API del proyecto, parte del valor estará oculta, por lo que no podrás recuperar una clave perdida.
Para reemplazar una credencial perdida o rotar una credencial sin interrumpir la carga de trabajo, sigue estos pasos:
- Declara la nueva cuenta como un recurso
openai_project_service_accountcon un nombre de recurso de Terraform distinto del de la cuenta anterior. - Aplica la configuración para crear la nueva cuenta de servicio.
- Agrega la nueva cuenta al grupo existente mediante
openai_group_userpara que herede el rol de proyecto con privilegios mínimos. - Crea una clave de API para la nueva cuenta mediante la API de administración y guárdala con el flujo de trabajo aprobado para tu gestor de secretos.
- Despliega la nueva clave y verifica que la carga de trabajo funcione con la nueva cuenta.
- Quita de la configuración de Terraform el recurso
openai_project_service_accountde la cuenta anterior y su recursoopenai_group_user. Conserva el rol, el grupo y la asignación del rol al grupo que sigue usando la nueva cuenta de servicio. - Revisa y aplica el plan que elimina la cuenta de servicio anterior y su pertenencia al grupo. Luego, ejecuta
terraform plany exige que el resultado no indique ningún cambio.
Al eliminar un recurso openai_project_service_account, se elimina la cuenta de servicio remota. Exige una revisión explícita de ese cambio, especialmente si la credencial anterior aún se usa para atender solicitudes.
Para obtener más información sobre cómo incorporar recursos al estado y cómo funciona su eliminación, consulta Importación y conciliación.
Ejecutar el ejemplo completo
Los ejemplos anteriores usan valores concretos para explicar cómo crear una cuenta de servicio, asignar un rol y crear una clave de API. La configuración completa usa variables para los valores y permisos específicos del proyecto, de modo que puedas reutilizarla en distintos entornos.
Guarda la siguiente configuración como 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
}
Crea terraform.tfvars con el ID de un proyecto existente, un nombre único para la cuenta de servicio y el conjunto mínimo de permisos de proyecto aprobados:
project_id = "proj_123"
service_account_name = "example-application-development-service-account"
project_role_permissions = [
"api.responses.write",
]
Inicializa Terraform y luego revisa y aplica un plan guardado:
terraform init
terraform fmt
terraform validate
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
El primer plan debería proponer agregar cinco recursos: la cuenta de servicio, su rol de proyecto personalizado, el grupo, la pertenencia de la cuenta al grupo y la asignación del rol al grupo. Vuelve a ejecutar terraform plan para confirmar que la configuración no produce más cambios.
Crea la clave de API de la cuenta de servicio fuera de Terraform:
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
Guarda el valor de la clave de API que recibiste en tu gestor de secretos aprobado y luego elimina service-account-api-key.json. No guardes la clave en la configuración, el estado ni las salidas de Terraform.