Saltar al contenido
BeryX
Volver a las respuestas para RFP

Documentación de BeryX

Este documento técnico está disponible en portugués.

Claude via Amazon Bedrock na conta AWS do cliente — onboarding IAM

BYOK 3 · ADR 0002, opção C · plano Enterprise (FEATURE_LLM_BYOK_CLOUD)

Clientes GCP: a mesma rota existe no Vertex AI, com impersonação de SA e sem chave JSON — docs/BYOK_VERTEX.md. Um workspace tem uma rota cloud (Bedrock ou Vertex).

Com esta rota, relatórios, sugestões, sinais, assistente, base de conhecimento e varredura de engenharia do BeryX correm no Claude da conta AWS da organização, numa região da UE. Os dados e a fatura dos tokens ficam na conta do cliente. A BeryxTech não guarda segredos: guarda o ARN de um role IAM e um ExternalId gerado por workspace, e obtém credenciais temporárias (15 min, só em memória) com sts:AssumeRole.

Como funciona

BeryX (runtime da BeryxTech)                    Conta AWS do cliente (eu-*)
───────────────────────────                   ───────────────────────────────────────────
identidade AWS da BeryxTech   ── sts:AssumeRole ─▶ role DataVaultBedrock
(LLM_BEDROCK_BROKER_PRINCIPAL)  + ExternalId      trust: principal da BeryxTech + ExternalId
                                                  policy: bedrock:InvokeModel* em eu.anthropic.*
credenciais temporárias    ── SigV4 ──────────▶ bedrock-runtime.<eu-região>.amazonaws.com
(só em memória, ≤15 min)                           inference profile eu.anthropic.claude-…
  • Residência: só são aceites regiões eu-* e ids de modelo eu.anthropic.* (inference profiles da UE). A política é verificada no domínio e na infra (providers/bedrock.py), por isso uma configuração fora dela nunca chega a assumir o role.
  • Confused deputy: o ExternalId é aleatório e único por workspace (dv-…). Sem ele na trust policy, o AssumeRole é recusado, mesmo que alguém saiba o ARN.
  • Falha: se o role deixar de funcionar (trust policy alterada, modelo sem acesso, 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 Bedrock 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 Bedrock numa tarefa, mas nunca o troca por outro.

Passo a passo

Em Equipa & Acessos → Claude via Amazon Bedrock (só administradores):

  1. Gerar ExternalId. A UI mostra o ExternalId do workspace e o principal da BeryxTech (o ARN que vai na trust policy).
  2. Criar o role na conta AWS (Terraform abaixo) e colar na UI o ARN do role, a região e o modelo. Ao guardar, fazemos um health-check: AssumeRole + um pedido de 1 token ao modelo (o Bedrock não tem Models API, e esta é a única prova de que o role pode invocá-lo nessa região). O custo é de ~10 tokens, na conta do cliente. Se falhar, nada é guardado e a mensagem diz o que corrigir (trust policy, permissões, acesso ao modelo, região).
  3. Correr o golden set. O golden set das sugestões (13 casos, GOLDEN v1) corre no modelo Bedrock 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 AWS e aparecem no FinOps (kind=golden). Com DATAVAULT_LLM_CLOUD_GOLDEN_JUDGE_MIN_SCORE > 0, o gate junta o juiz LLM do GOLDEN v2: 5 sugestões amostradas avaliadas pela cadeia dos relatórios, com a chave da BeryxTech, e a rota só ativa se a média das notas chegar a esse mínimo (sem fornecedor, reprova). O custo do juiz fica no FinOps como da BeryxTech (kind=golden, provider=anthropic).

Mudar o role, 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 de plano.

Terraform (conta do cliente)

variable "datavault_principal_arn" {
  description = "Principal AWS da BeryxTech (mostrado na UI, passo 1)"
  type        = string
}

variable "datavault_external_id" {
  description = "ExternalId do workspace BeryX (mostrado na UI, passo 1)"
  type        = string
}

variable "region" {
  description = "Região da UE onde o BeryX invoca o Claude"
  type        = string
  default     = "eu-central-1"
}

data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "datavault_trust" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "AWS"
      identifiers = [var.datavault_principal_arn]
    }
    condition {
      test     = "StringEquals"
      variable = "sts:ExternalId"
      values   = [var.datavault_external_id]
    }
  }
}

resource "aws_iam_role" "datavault_bedrock" {
  name                 = "DataVaultBedrock"
  assume_role_policy   = data.aws_iam_policy_document.datavault_trust.json
  max_session_duration = 3600
}

# Mínimo: invocar os inference profiles Claude da UE (e os modelos de base para
# onde o profile encaminha, nas regiões da UE). Nada de listagens nem de gestão.
data "aws_iam_policy_document" "datavault_invoke" {
  statement {
    sid     = "InvokeClaudeEuInferenceProfiles"
    actions = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
    resources = [
      "arn:aws:bedrock:${var.region}:${data.aws_caller_identity.current.account_id}:inference-profile/eu.anthropic.claude-*",
      "arn:aws:bedrock:eu-*::foundation-model/anthropic.claude-*",
    ]
  }
}

resource "aws_iam_role_policy" "datavault_invoke" {
  name   = "DataVaultBedrockInvoke"
  role   = aws_iam_role.datavault_bedrock.id
  policy = data.aws_iam_policy_document.datavault_invoke.json
}

output "datavault_role_arn" {
  value = aws_iam_role.datavault_bedrock.arn # colar na UI, passo 2
}

Antes de aplicar, garantir no console do Bedrock (região escolhida) que o acesso ao modelo Claude está concedido. Sem isso, o health-check devolve «O role não pode invocar este modelo». Para restringir mais, trocar eu.anthropic.claude-* pelo id exato do modelo escolhido. O CloudTrail do cliente regista cada sessão como datavault-<workspace_id>.

Modelos disponíveis

A allowlist é mantida pela BeryxTech (DEFAULT_BEDROCK_MODELS em backend/app/infra/llm/providers/bedrock.py). Por omissão tem Claude Haiku 4.5, Sonnet 5 e Opus 4.8, cada um com o seu inference profile eu.anthropic.…. Os ids mudam com as versões no Bedrock, e por isso podem ser substituídos sem deploy com LLM_BEDROCK_MODELS (JSON {"família": "eu.anthropic.…"}). Entradas fora de eu.anthropic.* são ignoradas. Confirmar os ids no console (Cross-region inference) antes de oferecer um modelo novo. Um modelo retirado da lista desliga a rota dos workspaces que o usavam (offline), até o admin escolher outro e o golden set passar.

Operação (BeryxTech)

  • Imagem: o extra [bedrock] (boto3) entra nas builds (CONNECTOR_EXTRAS), e os casos do golden set são copiados para /app/golden. Sem boto3, o health-check devolve sdk_unavailable (503 na API).
  • Identidade de origem: o runtime (Cloud Run) precisa de uma identidade AWS para chamar o STS, idealmente por federação de identidade (AWS_ROLE_ARN + AWS_WEB_IDENTITY_TOKEN_FILE com o token OIDC da service account) num role «broker» da BeryxTech sem outras permissões. O ARN desse role vai em LLM_BEDROCK_BROKER_PRINCIPAL e é o que os clientes põem na trust policy. O boto3 resolve a identidade pela cadeia por omissão. Nunca há chaves por workspace.
  • Custo: o preço Bedrock depende da região e do contrato do cliente, e por isso o FinOps mostra os tokens com custo — (nunca um número inventado) e remete para a fatura AWS.
  • Rotulagem art. 50.º: os outputs saem com «Claude …, Anthropic via Amazon Bedrock».
  • Sem Message Batches: o Bedrock não tem a Batches API. Os relatórios agendados desta rota correm pelo pedido síncrono.

API (admin)

Método Caminho O quê
GET /api/v1/workspace/llm-bedrock Estado, ExternalId, principal da BeryxTech, allowlist, último golden
POST /api/v1/workspace/llm-bedrock/prepare Gera o ExternalId (idempotente)
PUT /api/v1/workspace/llm-bedrock {role_arn, region, model}: grava se o health-check passar
POST /api/v1/workspace/llm-bedrock/golden Pede o golden set (fila; inline sem mensageria)
DELETE /api/v1/workspace/llm-bedrock Remove a rota (sem gate de plano)

Estados: draft → pending_golden → golden_running → active | golden_failed. Erros com code estável: region_not_allowed, invalid_role_arn, model_not_allowed (422), assume_role_denied, model_denied, model_not_found (422), unreachable (502), unavailable (503), not_prepared, not_configured, golden_running, already_active (409), e 402 fora do Enterprise. Tudo fica em admin-events (llm_byok_bedrock_*, categoria sensível byok), com a conta AWS, a região e o modelo, mas nunca o ExternalId.