Segurança e Autenticação

6 min de leitura

Segurança e Autenticação

O PgArachne depende inteiramente do sistema de permissões do PostgreSQL. Ele não reinventa Listas de Controle de Acesso (ACLs). O PgArachne suporta quatro métodos de autenticação. Os métodos 1–3 usam SET LOCAL ROLE para trocar de identidade; o método 4 (credenciais diretas) conecta-se diretamente como o usuário, portanto nenhuma troca de papel é necessária.

Isso se aplica aos endpoints JSON-RPC e MCP. O endpoint SSE é a única exceção — ele autentica quem chama, mas não troca de role nem verifica permissões por canal, já que os canais LISTEN/NOTIFY do PostgreSQL não são objetos de banco de dados com seus próprios GRANTs a aplicar. Veja a página de SSE para entender o que isso significa na prática.

1. Login Interativo (JWT)

Os usuários se autenticam usando seu nome de usuário e senha reais do PostgreSQL com autenticação HTTP Basic em POST /{prefix}/{database}/token. Em caso de sucesso, recebem um JWT de curta duração. As requisições subsequentes transportam esse token no cabeçalho Authorization: Bearer <token>, e o PgArachne altera o papel ativo para esse usuário durante toda a duração da requisição.

curl -X POST http://localhost:8080/db/my_database/token -u demo_user:user_password
→ {"token":"eyJhbGciOi...","token_type":"Bearer","expires_in":28800}

As credenciais trafegam no cabeçalho Authorization, nunca em um corpo JSON, e o login tem sua própria URL para que um proxy reverso possa limitar sua taxa sem ler corpos de requisição. A resposta nunca pode ser armazenada em cache.

Requer JWT_SECRET. Quando não está configurado, o endpoint retorna HTTP 404 (-32601) e os clientes usam credenciais diretas (método 4) ou tokens de API (método 2) em seu lugar.

2. Contas de Serviço (Tokens de API)

Para sistemas automatizados ou scripts, você pode usar chaves de API de longa duração.

  • Os tokens são armazenados na tabela pgarachne.api_tokens.
  • Cada token é mapeado para um usuário/papel de banco de dados específico.
  • Envie o token através do cabeçalho Authorization: Bearer <token>.

A criação de tokens de API requer o papel pgarachne_admin. Use pgarachne.add_api_token(...) com um papel membro de pgarachne_admin.

3. Provedor de identidade externo (JWT de terceiros)

Se você autentica usuários fora do PgArachne (por exemplo, em um serviço de autenticação externo), pode emitir os JWTs nesse serviço e enviá-los diretamente ao PgArachne.

  • Formato do cabeçalho: Authorization: Bearer <jwt>.
  • Assinatura: apenas HMAC (HS256/HS384/HS512) com o mesmo JWT_SECRET configurado no PgArachne.
  • Claims obrigatórios: db_role (string não vazia) e db_name (string que deve corresponder a /db/:database).
  • Claim obrigatório: exp (timestamp Unix) para expiração do token.

Requer JWT_SECRET; sem ele, valores Bearer são verificados apenas como tokens de API.

Exemplo mínimo de payload:

{
  "db_role": "demo_user",
  "db_name": "my_database",
  "exp": 1767225600
}

Importante: algoritmos JWT assimétricos (por exemplo, RS256/ES256) não são aceitos pela implementação atual do servidor.

4. Credenciais diretas do banco de dados (Basic Auth)

É possível enviar o nome de usuário e a senha do PostgreSQL diretamente via HTTP Basic Authentication, sem necessidade de token JWT ou token de API.

  • Formato do cabeçalho: Authorization: Basic <base64(usuario:senha)>
  • O PgArachne conecta-se ao PostgreSQL diretamente como esse usuário — nenhum SET LOCAL ROLE é executado.
  • Não é necessário executar GRANT usuario TO pgarachne.
  • Os pools de conexão são criados por usuário e têm tempo de vida de 5 minutos.

Exemplo com curl:

curl -u demo_user:senha \
  -X POST http://localhost:8080/db/meu_banco/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"api.hello_world","params":{},"id":1}'

Quando utilizar credenciais diretas

  • Desenvolvimento local — configuração rápida sem necessidade de emitir tokens.
  • Scripts internos — quando as credenciais já são gerenciadas com segurança pelo ambiente.
  • Serviços internos — integrações em redes privadas onde a gestão de tokens adiciona complexidade desnecessária.

Para ambientes de produção expostos à Internet ou integrações com clientes de IA em nuvem, os tokens de API (método 2) são preferíveis.

Principais diferenças em relação aos métodos baseados em token:

  • Não é necessário nenhum GRANT demo_user TO pgarachne — o PgArachne não troca de papel.
  • A segurança em nível de linha (Row-Level Security) e as permissões via GRANT do PostgreSQL são aplicadas normalmente, pois a conexão é executada como o próprio usuário.
  • Os pools de conexão são mantidos por usuário para maior eficiência, com um tempo de vida máximo de 5 minutos. Após uma alteração de senha, as conexões antigas expiram dentro dessa janela.
  • Para que as chaves de idempotência funcionem com credenciais diretas, conceda ao usuário EXECUTE ON FUNCTION pgarachne.save_idempotency_key(text, text).

Comparação dos métodos de autenticação

MétodoCabeçalhoSET LOCAL ROLEGRANT … TO pgarachneIdeal para
1. Login interativo (JWT)Authorization: Bearer <jwt>SimNecessárioAplicações web com utilizadores humanos
2. Contas de serviço (Token de API)Authorization: Bearer <token>SimNecessárioAutomação, scripts, clientes de IA em produção
3. JWT de terceirosAuthorization: Bearer <jwt>SimNecessárioIntegração com provedor de identidade externo
4. Credenciais diretas (Basic Auth)Authorization: Basic <base64>NãoNão necessárioDesenvolvimento, scripts, serviços internos

Configuração Crítica: Privilégios do Proxy

Quando o PgArachne utiliza os métodos 1, 2 ou 3, conecta-se ao PostgreSQL como o usuário definido em DB_USER (ex: pgarachne) e altera a identidade via SET LOCAL ROLE. Nesses casos, o usuário proxy deve ser membro dos papéis de destino.

Execute este SQL para cada usuário/papel que precisar utilizar os métodos 1–3:

-- Permitir que 'pgarachne' mude para 'demo_user'
GRANT demo_user TO pgarachne;

Este passo não é necessário quando se utilizam credenciais diretas (método 4).

Que funções podem ser chamadas

O PgArachne não tem uma lista própria de schemas permitidos — o que um papel pode chamar é decidido inteiramente pelos privilégios do PostgreSQL. Uma função pode ser chamada (e é listada por capabilities, pelo MCP tools/list e pela exportação OpenAPI) quando recebe um único parâmetro jsonb, o papel tem EXECUTE sobre ela e o papel tem USAGE sobre o seu schema. As funções em pg_catalog, information_schema, pgarachne e as que pertencem a extensões são omitidas da listagem para a manter legível, mas aplicam-se-lhes os mesmos privilégios.

As predefinições do PostgreSQL são permissivas

Por predefinição, o PostgreSQL concede EXECUTE sobre cada nova função a PUBLIC, e todos os papéis têm USAGE sobre o schema public. Uma função auxiliar public.something(jsonb) pode, portanto, ser chamada através da API por qualquer papel autenticado, a menos que revogue o privilégio. Configuração recomendada:

-- As novas funções não são executáveis por todos (executar como o papel que as cria):
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

-- Mantenha as funções da API num schema dedicado e conceda privilégios explicitamente:
GRANT USAGE ON SCHEMA api TO demo_user;
GRANT EXECUTE ON FUNCTION api.hello_world(jsonb) TO demo_user;

Proteção contra força bruta

LOGIN_RATE_LIMIT e LOGIN_RATE_LIMIT_PER_IP se aplicam a todos os métodos de autenticação, em todos os endpoints (JSON-RPC, MCP, SSE, OpenAPI):

  • /token: cada tentativa conta para os limites por (IP, nome de usuário) e por IP.
  • Credenciais diretas (Basic Auth): tentativas falhas contam para os limites por (IP, nome de usuário) e por IP. Requisições bem-sucedidas não são contadas, então um cliente legítimo que envia credenciais em toda requisição nunca é limitado.
  • Tokens Bearer (JWT ou token de API): tentativas falhas contam para o limite por IP.

Quando um limite se esgota, novas tentativas são rejeitadas com HTTP 429 até que a janela (LOGIN_RATE_WINDOW) termine — sem sequer verificar as credenciais.