Saltar para o conteúdo
BeryX
Voltar às respostas para RFP

Documentação do BeryX

Claude via Google Cloud Vertex AI na conta GCP do cliente — onboarding IAM

BYOK 4 · ADR 0002, opção D · plano Enterprise (FEATURE_LLM_BYOK_CLOUD)

Com esta rota, relatórios, sugestões, sinais, assistente, base de conhecimento e varredura de engenharia do BeryX correm no Claude do projeto Google Cloud da organização, num endpoint regional da UE (europe-*). Os dados e a fatura dos tokens ficam na conta do cliente. Não há chaves JSON em lado nenhum: a BeryxTech impersona uma service account (SA) do cliente a partir da identidade do seu próprio runtime (Cloud Run) e obtém um access token de curta duração (15 min, só em memória). A BeryxTech guarda só o email da SA, o projeto, a região, o modelo e um token de verificação gerado por workspace — nenhum deles é uma credencial.

É o mesmo ciclo da rota Bedrock (docs/BYOK_BEDROCK.md): as duas são casos da abstração «Claude na conta cloud do cliente» (app/infra/llm/providers/cloud.py + app/domain/llm/cloud_route.py). Um workspace tem uma rota cloud: Bedrock ou Vertex.

Como funciona

BeryX (Cloud Run da BeryxTech)                  Projeto GCP do cliente (europe-*)
───────────────────────────────                  ──────────────────────────────────────────────
SAs de runtime (Workload Identity) ─ generateAccessToken ─▶ SA datavault-claude@<projeto>
 datavault-api@…    (health-check)    iamcredentials API     Token Creator: os 2 principais
 datavault-worker@… (golden set, IA)                         da BeryxTech (LLM_VERTEX_BROKER_PRINCIPAL)
                                                           description: «… dv-<token> …»
token impersonado (15 min) ─ GET serviceAccounts/<sa> ──▶ prova de posse (lê a description)
(só em memória)            ─ AsyncAnthropicVertex ──────▶ <região>-aiplatform.googleapis.com
                                                           publishers/anthropic/models/claude-…
  • Sem chave JSON: o token de origem vem do servidor de metadados do Cloud Run (Workload Identity). Em desenvolvimento local, com google-auth instalado, usam-se as ADC (gcloud auth application-default login). Nenhuma chave de SA é criada, enviada ou guardada.
  • Residência: só regiões europe-* (nunca o endpoint global nem regiões fora da UE) e ids de modelo claude-… da allowlist da BeryxTech. A política é verificada no domínio e na infra (providers/vertex.py), por isso uma configuração fora dela nunca chega a pedir um token.
  • Dois principais, uma identidade por passo: o health-check do passo 2 corre na api (datavault-api@…) e o golden set e a IA correm no worker (datavault-worker@…) — cada serviço Cloud Run da BeryxTech tem a sua service account dedicada, com acesso só ao que monta (docs/DEPLOY_GCP.md §14). O cliente concede Token Creator às duas; com uma só, metade do ciclo falha com impersonation_denied.
  • Confused deputy: o GCP não tem ExternalId. Qualquer cliente da BeryxTech concede Token Creator aos mesmos principais da BeryxTech — sem mais nada, um tenant podia apontar para a SA de outro. Por isso a SA tem de trazer na description o token de verificação do workspace (dv-…), e o health-check lê-a com o token impersonado: só passa quem controla aquela SA.
  • Falha: se a SA deixar de funcionar (Token Creator removido, modelo desativado, quota), a IA degrada para os modos offline (heurísticas e templates) e o evento fica como llm.byok_error. Nunca caímos para a conta da BeryxTech contra a escolha do cliente.
  • Precedência: uma rota Vertex ativa substitui a chave Anthropic própria (BYOK 1), se existir.
  • Model policy (BYOK 2): «IA desligada» e as restrições de modelos por tarefa continuam a aplicar-se. A policy pode recusar o modelo Vertex numa tarefa, mas nunca o troca por outro.
  • Sem Message Batches: os pedidos que na rota da BeryxTech iriam em batch correm síncronos.

Passo a passo

Em Equipa & Acessos → Claude via Google Cloud Vertex AI (só administradores):

  1. Gerar o token de verificação. A UI mostra o token do workspace (dv-…), os principais da BeryxTech (as duas service accounts de runtime do Cloud Run: datavault-api@…, que valida a ligação no passo 2, e datavault-worker@…, que corre o golden set e a IA) e os comandos gcloud abaixo já preenchidos, com um binding Token Creator por principal.
  2. Preparar a SA no projeto (gcloud ou Terraform abaixo), ativar o modelo Claude no Model Garden do projeto e colar na UI o email da SA, o ID do projeto, a região e o modelo. Ao guardar, fazemos um health-check: impersonação + prova de posse + um pedido de 1 token ao modelo (custo ~10 tokens, na conta do cliente). Se falhar, nada é guardado e a mensagem diz o que corrigir (Token Creator, token na descrição, aiplatform.user, modelo, região).
  3. Correr o golden set. O golden set das sugestões (13 casos, GOLDEN v1) corre no modelo Vertex escolhido, no worker (fila llm.golden.requested). A rota só fica ativa se passar (limiar DATAVAULT_LLM_CLOUD_GOLDEN_THRESHOLD, por omissão 100%). Reprovado, fica em golden_failed, com os casos que falharam, e a IA continua como estava. Os tokens do golden set são faturados na conta GCP e aparecem no FinOps (kind=golden, provider=vertex). Com DATAVAULT_LLM_CLOUD_GOLDEN_JUDGE_MIN_SCORE > 0, o gate junta o juiz LLM do GOLDEN v2, como no Bedrock (docs/BYOK_BEDROCK.md §3).

Mudar a SA, o projeto, a região ou o modelo invalida a aprovação: o golden set tem de passar outra vez nesse modelo. Remover a rota é sempre possível, mesmo depois de um downgrade.

gcloud (projeto do cliente)

PROJETO=banco-ia-prod                                   # o vosso projeto
SA=datavault-claude@${PROJETO}.iam.gserviceaccount.com
TOKEN=dv-…                                              # passo 1 da UI
PRAXIS_API=datavault-api@praxis-….iam.gserviceaccount.com       # principais da BeryxTech (passo 1 da UI):
PRAXIS_WORKER=datavault-worker@praxis-….iam.gserviceaccount.com # api = health-check, worker = golden set e IA

gcloud services enable aiplatform.googleapis.com --project="$PROJETO"

# 1. A SA que o BeryX vai usar, com o token de verificação na descrição.
gcloud iam service-accounts create datavault-claude --project="$PROJETO" \
  --display-name="BeryX (BeryxTech) — Claude" \
  --description="BeryX · BeryxTech — ${TOKEN}"
#    (SA já existente: gcloud iam service-accounts update "$SA" --description="… ${TOKEN}")

# 2. Pode invocar modelos no Vertex AI deste projeto.
gcloud projects add-iam-policy-binding "$PROJETO" \
  --member="serviceAccount:${SA}" --role=roles/aiplatform.user

# 3. Pode ler-se a si própria (prova de posse: o BeryX lê a descrição com o token dela).
gcloud iam service-accounts add-iam-policy-binding "$SA" --project="$PROJETO" \
  --member="serviceAccount:${SA}" --role=roles/iam.serviceAccountViewer

# 4. A BeryxTech pode impersoná-la — e só a ela (binding na SA, não no projeto) — a
#    partir das duas SAs de runtime: um binding por principal.
for PRAXIS in "$PRAXIS_API" "$PRAXIS_WORKER"; do
  gcloud iam service-accounts add-iam-policy-binding "$SA" --project="$PROJETO" \
    --member="serviceAccount:${PRAXIS}" --role=roles/iam.serviceAccountTokenCreator
done

Depois, no Model Garden do projeto, ativar o(s) modelo(s) Claude escolhido(s) (aceitar os termos da Anthropic no Marketplace). Para restringir a SA a Claude, pode trocar-se roles/aiplatform.user por um role personalizado com aiplatform.endpoints.predict.

Terraform (projeto do cliente)

variable "project_id" { type = string }
variable "datavault_principals" {
  description = "Principais da BeryxTech (SAs de runtime do Cloud Run: api e worker, mostrados na UI, passo 1)"
  type        = list(string)
}
variable "datavault_verification_token" {
  description = "Token de verificação do workspace (UI, passo 1)"
  type        = string
}

resource "google_project_service" "aiplatform" {
  project = var.project_id
  service = "aiplatform.googleapis.com"
}

resource "google_service_account" "datavault" {
  project      = var.project_id
  account_id   = "datavault-claude"
  display_name = "BeryX (BeryxTech) — Claude"
  description  = "BeryX · BeryxTech — ${var.datavault_verification_token}"
}

resource "google_project_iam_member" "datavault_vertex" {
  project = var.project_id
  role    = "roles/aiplatform.user"
  member  = "serviceAccount:${google_service_account.datavault.email}"
}

resource "google_service_account_iam_member" "datavault_self_viewer" {
  service_account_id = google_service_account.datavault.name
  role               = "roles/iam.serviceAccountViewer"
  member             = "serviceAccount:${google_service_account.datavault.email}"
}

resource "google_service_account_iam_member" "praxis_token_creator" {
  for_each           = toset(var.datavault_principals)
  service_account_id = google_service_account.datavault.name
  role               = "roles/iam.serviceAccountTokenCreator"
  member             = "serviceAccount:${each.value}"
}

output "datavault_service_account" {
  value = google_service_account.datavault.email
}

Do lado da BeryxTech (operação)

  • LLM_VERTEX_BROKER_PRINCIPAL = os emails das duas SAs de runtime do Cloud Run do BeryX, separados por vírgula: datavault-api@<projeto>.iam.gserviceaccount.com (o health-check do passo 2 corre na api) e datavault-worker@<projeto>.iam.gserviceaccount.com (o golden set e a IA correm no worker). O deploy/gcp_deploy.sh define-a nos dois serviços. É só informativo (mostrado no onboarding, que gera um binding por principal); a identidade real é a da revisão que chama. Cada serviço corre com a sua SA dedicada, sem roles/editor e só com os segredos que monta (docs/DEPLOY_GCP.md §14, cartão #279).
  • A API IAM Service Account Credentials (iamcredentials.googleapis.com) tem de estar ativa no projeto da BeryxTech (deploy/gcp_deploy.sh ativa-a).
  • LLM_VERTEX_MODELS (JSON {família: id}) substitui a allowlist por omissão sem deploy — os ids do Vertex mudam com as versões (claude-…@AAAAMMDD). Entradas fora do formato saem.
  • Não é preciso nenhum extra Python: o token de origem vem do servidor de metadados por httpx e o AsyncAnthropicVertex recebe um access_token já pronto (sem google-auth).
  • Auditoria: llm_byok_vertex_prepared|configured|golden_requested|activated|golden_failed|removed (categoria sensível byok), com o projeto GCP e nunca o token de verificação.

Migração — tenants configurados antes das SAs dedicadas (setembro de 2026)

Até ao cartão #279 o principal da BeryxTech era a compute SA por omissão do projeto (<nº>-compute@developer.gserviceaccount.com). Um workspace Vertex configurado antes disso tem Token Creator concedido a essa SA — e a essa SA só. Depois do cutover (docs/DEPLOY_GCP.md §14.2), a api e o worker chamam com datavault-api@… e datavault-worker@…: sem os bindings novos, o health-check e o golden set falham com impersonation_denied e a IA degrada para os modos offline (nunca para a conta da BeryxTech).

O que o cliente faz, antes de a BeryxTech retirar o Editor à compute SA:

for PRAXIS in "$PRAXIS_API" "$PRAXIS_WORKER"; do        # os dois emails do passo 1 da UI
  gcloud iam service-accounts add-iam-policy-binding "$SA" --project="$PROJETO" \
    --member="serviceAccount:${PRAXIS}" --role=roles/iam.serviceAccountTokenCreator
done
# depois de a BeryxTech confirmar o cutover: retirar o binding antigo
gcloud iam service-accounts remove-iam-policy-binding "$SA" --project="$PROJETO" \
  --member="serviceAccount:<nº>-compute@developer.gserviceaccount.com" --role=roles/iam.serviceAccountTokenCreator

Em Terraform: trocar datavault_principal (string) por datavault_principals (lista com os dois emails) — o for_each acima cria um binding por principal. Confirmar na UI com «Validar ligação e guardar» (passo 2) e, se a rota estava ativa, «Correr golden set» de novo não é preciso: a aprovação é por modelo, não por principal.