Skip to main content

Arquitetura do Vault

Esta página é uma referência técnica para operadores e colaboradores preocupados com segurança que desejam entender como a integração do vault da Switchbord funciona de ponta a ponta. Para instruções de configuração, veja Configuração do Vault.

Modelo de Armazenamento

A Switchbord usa duas camadas de objetos de banco de dados para armazenar segredos de workspace: vault.secrets (nativo do Supabase) Os valores dos segredos efetivamente criptografados residem aqui. Cada linha contém uma coluna secret criptografada com pgsodium (AES-256-GCM), uma coluna name para identificação legível por humanos, e um key_id referenciando a chave pgsodium usada para a criptografia. As linhas são identificadas por um UUID. app_private.workspace_secret_bindings (personalizado da Switchbord) Esta tabela mapeia um workspace aos seus segredos:
A tabela de bindings não contém, ela própria, nenhum dado sensível. É puramente um ponteiro: para o workspace X e o tipo de segredo Y, procure o segredo do vault Z. A descriptografia efetiva ocorre em vault.secrets.

Por que o Schema app_private

O schema app_private é usado para tabelas e funções que não devem ser expostas via PostgREST (a API REST auto-gerada do Supabase). Por padrão, o PostgREST expõe apenas objetos do schema public (e schemas explicitamente listados em db_schema). Colocar workspace_secret_bindings em app_private garante que:
  • Nenhum cliente anônimo ou autenticado possa executar SELECT diretamente na tabela de bindings via a biblioteca cliente do Supabase
  • Nenhum endpoint REST para /app_private/workspace_secret_bindings seja gerado
  • O acesso só seja possível por meio de funções explicitamente definidas que executam como SECURITY DEFINER
A segurança em nível de linha (row-level security) também está habilitada em workspace_secret_bindings como uma medida de defesa em profundidade, mas a colocação no schema app_private é a camada de isolamento primária.
O padrão de schema app_private é uma convenção padrão do Supabase para objetos de schema sensíveis. Ele é documentado nos próprios guias de “Row Level Security” e “Functions” do Supabase como a forma recomendada de proteger dados que nunca devem ser acessíveis diretamente.

Arquitetura do Caminho de Leitura

O caminho de leitura foi projetado para evitar exigir uma conexão direta ao banco de dados a partir do serviço worker. Todas as leituras sensíveis passam por funções RPC do Supabase definidas com SECURITY DEFINER.

Funções SECURITY DEFINER

Para garantir que os itens do vault nunca sejam expostos via o schema public padrão ou endpoints REST auto-gerados, a Switchbord usa o padrão de schema app_private. app_private.read_workspace_secret Junta app_private.workspace_secret_bindings com vault.decrypted_secrets para retornar o valor em texto puro. Executa como SECURITY DEFINER, permitindo acesso ao schema vault, que normalmente é restrito. app_private.resolve_workspace_by_verify_token Usada durante a verificação de webhook da Meta para rotear requisições ao workspace correto sem expor tokens ao cliente.

Wrappers RPC Públicos

Como o PostgREST expõe apenas o schema public, fornecemos wrappers finos que aplicam a autorização:
  • public.sb_read_workspace_secret: Valida auth.role() == 'service_role' antes de delegar à função privada.
  • public.sb_resolve_workspace_by_verify_token: Segue o mesmo padrão de segurança para resolução de token.
Esses wrappers rejeitam explicitamente chamadas feitas com a chave anon ou um JWT escopado ao usuário. Somente a chave de service role (SUPABASE_SECRET_KEY) pode invocá-los. Isso é aplicado no nível SQL por meio de verificações de auth.role() dentro das funções wrapper.

Caminho de Gravação

O caminho de gravação passa pela aplicação web da Switchbord e não envolve o worker:
O caminho de gravação usa uma conexão direta ao Postgres (SUPABASE_DB_URL) ao chamar vault.create_secret() de fora do servidor da aplicação, mas a rota de API Next.js trata isso usando o cliente de service role do Supabase. Quem faz self-hosting não precisa de SUPABASE_DB_URL no worker — apenas na aplicação web, se gravações no vault forem necessárias a partir de código do lado do servidor.

Criptografia em Repouso

O Supabase Vault usa pgsodium, uma extensão do PostgreSQL que envolve a libsodium.
  • Algoritmo: XChaCha20-Poly1305 (uma cifra de fluxo com autenticação)
  • Gestão de chaves: o pgsodium usa uma chave raiz derivada de um segredo armazenado fora do banco de dados (na infraestrutura de gestão de chaves do Supabase para Cloud, ou configurada separadamente para self-hosted)
  • Escopo de criptografia: cada segredo em vault.secrets é criptografado com uma chave derivada da chave raiz. O texto cifrado e o ID da chave são armazenados juntos; o texto puro nunca é persistido.
  • Descriptografia: a view vault.decrypted_secrets realiza a descriptografia de forma transparente usando pgsodium.crypto_aead_det_decrypt(). Somente papéis de banco de dados com permissão de SELECT nessa view podem ler valores em texto puro.
Para implantações Supabase Cloud, a chave raiz do pgsodium é gerenciada pelo Supabase e nunca é exposta aos proprietários do projeto. Para Supabase self-hosted, você é responsável por proteger a chave raiz — veja o guia de self-hosting do Supabase para configuração de chaves.

Resumo do Controle de Acesso

O worker autentica todas as chamadas RPC usando o JWT de service role (SUPABASE_SECRET_KEY). Essa chave deve permanecer secreta e nunca deve ser exposta a clientes de navegador ou registrada em logs.

Referência de Migração

A integração do vault é composta por duas camadas: Nativo do Supabase (nenhuma ação necessária)
  • Schema vault e tabela vault.secrets
  • View vault.decrypted_secrets
  • Função vault.create_secret()
  • Extensão pgsodium
Esses objetos estão presentes em todos os projetos Supabase Cloud e podem ser habilitados em Supabase self-hosted via CREATE EXTENSION supabase_vault. Personalizado da Switchbord (aplicado via migrations)
  • Criação do schema app_private
  • Tabela app_private.workspace_secret_bindings
  • Função app_private.read_workspace_secret()
  • Função app_private.resolve_workspace_by_verify_token()
  • Wrapper public.sb_read_workspace_secret()
  • Wrapper public.sb_resolve_workspace_by_verify_token()
Esses objetos são criados pelas migrations de banco de dados da Switchbord em supabase/migrations/. Executar supabase db push aplica todas as migrations pendentes e garante que esses objetos existam. Se você precisar inspecionar as definições de função diretamente:

Considerações de Segurança para Quem Faz Self-Hosting

Exposição da chave de service role A SUPABASE_SECRET_KEY pode chamar qualquer função RPC e contorna o RLS. Trate-a com o mesmo cuidado que uma senha raiz de banco de dados. Rotacione-a imediatamente se suspeitar de exposição. Chave pgsodium do Supabase self-hosted Se estiver executando o Supabase localmente ou em sua própria infraestrutura, a chave raiz do pgsodium deve ser definida antes que qualquer segredo seja armazenado. Se a chave for alterada ou perdida, todos os segredos do vault armazenados se tornam irrecuperáveis — não há custódia de chave (key escrow). Integridade das migrations As funções SECURITY DEFINER em app_private são tão seguras quanto o papel proprietário do banco de dados. Garanta que somente partes de confiança tenham a capacidade de redefinir ou substituir essas funções via migrations.

Guias Relacionados