Uma conta de serviço da OpenAI é uma identidade não humana que pertence a um projeto. Com o Terraform, você pode criar a conta sem uma função padrão, definir um conjunto mínimo de permissões e atribuí-lo à conta por meio de um grupo. Use a API de administração para criar e gerenciar as chaves de API da conta de serviço fora do Terraform.
Este guia apresenta as etapas típicas de configuração de uma conta de serviço:
- Crie uma conta de serviço sem função padrão no projeto e sem chave de API.
- Atribua uma função de projeto personalizada por meio de um grupo, concedendo apenas as permissões necessárias à carga de trabalho.
- Crie uma chave de API com escopo delimitado e armazene-a no seu gerenciador de segredos.
Antes de começar
Conclua a configuração do provedor do Terraform, exporte uma chave da API de administração como OPENAI_ADMIN_KEY e exporte o ID do projeto existente como PROJECT_ID.
Use uma organização de teste para avaliar a criação, a importação, a substituição e a exclusão de contas de serviço.
Crie uma conta de serviço sem função padrão
Crie a conta de serviço com o 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
}
Substitua proj_123 pelo ID do projeto existente ao qual a conta de serviço pertencerá.
O provedor cria a identidade da conta de serviço sem gerar uma chave de API nem atribuir uma função padrão no projeto. O Terraform armazena no estado o ID da conta de serviço e outros metadados não sensíveis. Nesta etapa, a conta de serviço não tem permissões no projeto.
Atribua apenas as permissões necessárias
Defina uma função de projeto personalizada com apenas as permissões necessárias à carga de trabalho. Crie um grupo, adicione a conta de serviço a ele e atribua a função ao grupo. Neste exemplo, os membros do grupo podem criar respostas:
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
}
O recurso openai_project_role define o conjunto mínimo de permissões, openai_group_user adiciona a conta de serviço ao grupo e openai_project_group_role atribui a função a esse grupo. Toda conta de serviço adicionada ao grupo herda a mesma função de projeto. Substitua api.responses.write pelo conjunto mínimo de permissões aprovadas para sua carga de trabalho. Consulte Projetos e acesso para saber mais sobre como conceder acesso a projetos por meio de grupos.
Revise e aplique a configuração:
terraform plan
terraform apply
Não atribua as funções predefinidas member ou owner quando uma função de projeto personalizada
oferecer as permissões necessárias à sua carga de trabalho. Limite o acesso ao
conjunto de permissões aprovado.
Crie uma chave de API com escopo delimitado
Depois de aplicar a configuração do Terraform, crie uma chave de API pelo endpoint Criar uma chave de API para uma conta de serviço do projeto. A API retorna o valor completo da chave apenas uma vez. Por isso, proteja o arquivo de resposta antes de fazer a solicitação:
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
Escolha os escopos mais restritos que atendam às necessidades da carga de trabalho. Os escopos da chave de API podem restringir ainda mais as permissões da conta de serviço, mas não podem conceder permissões além das previstas na função de projeto atribuída à conta.
Encaminhe o conteúdo do campo value de service-account-api-key.json ao seu gerenciador de segredos pelo procedimento aprovado, sem exibir o valor. Depois que o gerenciador armazenar e verificar o segredo, exclua o arquivo de resposta:
rm service-account-api-key.json
Trate service-account-api-key.json como um segredo enquanto o arquivo existir. Não inclua o arquivo em um commit, não grave a chave na configuração do Terraform, não a exponha em uma saída do Terraform nem a passe como variável do Terraform.
A referência da API apresenta a estrutura da resposta e exemplos por linguagem. Cargas de trabalho compatíveis com a federação de identidades de cargas de trabalho podem usar a mesma conta de serviço e a mesma função de privilégio mínimo sem criar uma chave de API.
Importe uma conta de serviço existente
Não é necessário importar uma conta de serviço criada pelo Terraform. Para passar a gerenciar uma conta de serviço criada fora do Terraform, declare-a com o mesmo ID de projeto e o mesmo nome:
resource "openai_project_service_account" "application" {
project_id = "proj_123"
name = "example-application-development-service-account"
}
Importe a identidade existente antes de aplicar a configuração normalmente:
SERVICE_ACCOUNT_ID="<existing-service-account-id>"
terraform import \
openai_project_service_account.application \
"$PROJECT_ID/$SERVICE_ACCOUNT_ID"
terraform plan
O primeiro plano após a importação não deve propor alterações na conta de serviço. Se o plano propuser uma substituição, ajuste o nome e o projeto na configuração para que correspondam aos da conta existente antes de aplicar o plano.
A importação não recupera nem armazena chaves de API, não altera a função de projeto que a conta de serviço já tem e não importa o vínculo da conta com o grupo. Declare e importe os recursos existentes openai_project_role, openai_group, openai_group_user e openai_project_group_role se o Terraform for gerenciá-los. A carga de trabalho continua lendo os segredos existentes do seu gerenciador de segredos.
Importe a conta de serviço antes de aplicar a declaração do recurso. Se você aplicar a declaração primeiro, o Terraform criará outra conta de serviço em vez de passar a gerenciar a identidade existente.
Recupere ou rotacione credenciais
O valor completo da chave de API só está disponível na resposta à solicitação de criação da chave. Consultas posteriores à chave de API do projeto retornam um valor mascarado. Por isso, não é possível recuperar uma chave perdida.
Para substituir uma credencial perdida ou fazer a rotação sem interromper a carga de trabalho, siga estas etapas:
- Declare a nova conta como um novo recurso
openai_project_service_account, com um nome de recurso do Terraform diferente do usado para a conta antiga. - Aplique a configuração para criar a nova conta de serviço.
- Adicione a nova conta ao grupo existente com
openai_group_userpara que ela herde a função de projeto com privilégio mínimo. - Crie uma chave de API para a nova conta pela API de administração e armazene-a no gerenciador de segredos seguindo o procedimento aprovado.
- Implante a nova chave e verifique se a carga de trabalho funciona com a nova conta.
- Remova da configuração do Terraform o recurso
openai_project_service_accountda conta antiga e o respectivo recursoopenai_group_user. Mantenha a função, o grupo e a atribuição da função ao grupo que a nova conta de serviço ainda usa. - Revise e aplique o plano que exclui a conta de serviço antiga e seu vínculo com o grupo. Em seguida, execute
terraform plane exija que o resultado não indique nenhuma alteração.
Excluir um recurso openai_project_service_account exclui a conta de serviço remota. Exija uma revisão explícita dessa alteração, principalmente enquanto a credencial antiga ainda estiver em uso para atender a solicitações.
Para saber mais sobre como incorporar recursos ao estado e removê-los, consulte Importação e reconciliação.
Execute o exemplo completo
Os exemplos anteriores usam valores concretos para explicar como criar uma conta de serviço, atribuir uma função e criar uma chave de API. A configuração completa usa variáveis para os valores e as permissões específicos de cada projeto, para que você possa reutilizá-la em diferentes ambientes.
Salve a configuração a seguir 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
}
Crie terraform.tfvars com o ID de um projeto existente, um nome exclusivo para a conta de serviço e o conjunto mínimo de permissões de projeto aprovadas:
project_id = "proj_123"
service_account_name = "example-application-development-service-account"
project_role_permissions = [
"api.responses.write",
]
Inicialize o Terraform e, em seguida, revise e aplique um plano salvo:
terraform init
terraform fmt
terraform validate
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
O primeiro plano deve propor a adição de cinco recursos: a conta de serviço, sua função de projeto personalizada, o grupo, o vínculo da conta com o grupo e a atribuição da função ao grupo. Execute terraform plan novamente para confirmar que a configuração não gera outras alterações.
Crie a chave de API da conta de serviço fora do 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
Transfira o valor da chave de API retornado na resposta para o gerenciador de segredos aprovado e exclua service-account-api-key.json. Não armazene a chave na configuração, no estado nem nas saídas do Terraform.