Saltar para o conteúdo principal

Armazenamento e base de dados

Armazenamento de blobs​

As mensagens em bruto, os anexos e os ficheiros vivem em armazenamento de objetos. O Postgres guarda os metadados e quem os usa. Cada ficheiro é guardado uma vez por espaço de trabalho, sob o seu SHA-256, por mais mensagens que o transportem. Um ficheiro que já ninguém usa é eliminado por uma limpeza horária depois de passadas CAMPBOOKS_BLOBS__SWEEP_GRACE_HOURS horas (24 por omissão). Os ficheiros maiores do que CAMPBOOKS_BLOBS__MAX_OBJECT_BYTES (50 MiB por omissão) são recusados.

Disco local (por omissão)​

CAMPBOOKS_BLOBS__BACKEND=fs guarda os ficheiros em CAMPBOOKS_BLOBS__PATH (/data/blobs, o volume blobs-data). As escritas são atómicas: um ficheiro temporário, escrito em disco e depois renomeado para o lugar final.

Armazenamento compatível com S3​

Qualquer armazenamento que fale a API S3 serve (AWS S3, Garage, MinIO, Ceph, Cloudflare R2). Crie um bucket privado e uma chave de acesso limitada a ele, e depois defina isto no .env:

CAMPBOOKS_BLOBS__BACKEND=s3
CAMPBOOKS_BLOBS__S3__BUCKET=campbooks-blobs
CAMPBOOKS_BLOBS__S3__ENDPOINT=https://s3.example.com # unset for AWS
CAMPBOOKS_BLOBS__S3__REGION=us-east-1 # what your store expects
CAMPBOOKS_BLOBS__S3__ACCESS_KEY_ID=...
CAMPBOOKS_BLOBS__S3__SECRET_ACCESS_KEY=...
CAMPBOOKS_BLOBS__S3__PATH_STYLE=true # most self-hosted stores

O servidor verifica no arranque se consegue chegar ao bucket e recusa-se a arrancar caso contrário. Os envios grandes são feitos por partes. Acrescente ao bucket uma regra de ciclo de vida que aborte os envios em partes incompletos ao fim de um dia, para que uma falha a meio de um envio não deixe lixo. O volume blobs-data não é usado com este backend.

Cifragem em repouso​

O Campbooks ainda não cifra os ficheiros por si. Use a cifragem do seu armazenamento: cifragem do lado do servidor no bucket, ou um disco cifrado sob blobs-data no backend local.

Mudar de backend​

Copie a árvore inteira (chaves <workspace>/<aa>/<sha256>, com exceção do prefixo _staging/) para o novo armazenamento com o servidor parado e depois mude as definições. As chaves são idênticas em disco e num bucket.

Contas da base de dados​

O Postgres ignora a segurança ao nível da linha para superutilizadores e papéis BYPASSRLS. Uma consulta que consiga fazer RESET ROLE também pode recuperar os poderes da própria conta. Por isso o servidor usa duas contas:

ContaDefiniçãoUsada paraTem de ser
execuçãoCAMPBOOKS_DATABASE_URL (e CAMPBOOKS_DATABASE_PASSWORD_FILE, opcional)cada pedido e tarefaLOGIN, não superutilizador, sem BYPASSRLS, não possui nada, membro de campbooks_app
migraçãoCAMPBOOKS_DATABASE_MIGRATION_URLaplicar migrações no arranque, nada maiso proprietário do esquema (ou um superutilizador)

Postgres incluído​

Nada a fazer. O serviço de execução única db-init cria a conta campbooks_runtime em cada up (é idempotente e também atualiza uma instalação existente). Gera a palavra-passe uma só vez para o volume db-secrets, e o servidor lê-a de /run/db/runtime-password. A conta proprietária continua a ser campbooks com POSTGRES_PASSWORD, usada só para migrações.

Para renovar a palavra-passe de execução, elimine o ficheiro no volume e arranque de novo:

docker compose run --rm --entrypoint rm db-init /run/db/runtime-password
docker compose up -d

O seu próprio Postgres ou um gerido​

Crie a conta uma vez, como administrador. As migrações concedem depois a campbooks_app o que cada tabela precisa.

CREATE ROLE campbooks_app NOLOGIN; -- skip if it exists
CREATE ROLE campbooks_runtime LOGIN PASSWORD '...' NOSUPERUSER NOBYPASSRLS
NOCREATEDB NOCREATEROLE;
GRANT campbooks_app TO campbooks_runtime;
-- Allow the migration user to run the first migration's grants:
GRANT campbooks_app TO <migration user>; -- skip for a superuser

Depois defina CAMPBOOKS_DATABASE_URL=postgres://campbooks_runtime:<password>@host/db, ou omita a palavra-passe e aponte CAMPBOOKS_DATABASE_PASSWORD_FILE para um ficheiro que a contenha. Defina CAMPBOOKS_DATABASE_MIGRATION_URL com o URL do proprietário. Nos serviços geridos, o proprietário é o utilizador que criou a base de dados. Não o reutilize como conta de execução.

Precisa também do pgvector, que a imagem incluída (pgvector/pgvector:pg17) já traz.

Isolamento dos espaços de trabalho​

As linhas de cada espaço de trabalho são protegidas pela segurança ao nível da linha do Postgres, além das consultas. O servidor consulta com uma conta que não consegue contornar as políticas e recusa-se a arrancar se conseguisse.

No arranque, o servidor recusa-se a arrancar, e diz porquê, quando o papel com que consulta:

  • é um superutilizador,
  • tem BYPASSRLS,
  • é membro de um papel desses, ou
  • possui tabelas com segurança ao nível da linha.

Quando está configurada uma conta de migração, recusa-se também se a conta de execução ainda puder mudar para um papel privilegiado. Só a configuração antiga com um único URL (uma conta privilegiada que executa SET ROLE campbooks_app) continua a funcionar, com um aviso para separar as contas. Se ainda não o conseguir fazer, veja Resolução de problemas.