Ir para o conteúdo

Primeira execução e configuração

Tanto o peart quanto o peart-portal leem o mesmo arquivo de configuração, /etc/peart/config.yaml. Copie do exemplo distribuído e edite; o exemplo não roda como está.

sudo install -d -o peart -g peart-portal -m 0710 /etc/peart
sudo install -o peart -g peart-portal -m 0640 config.example.yaml /etc/peart/config.yaml
sudo install -o root -g root -m 0600 /dev/null /etc/peart/peart.env
sudo install -o root -g root -m 0600 /dev/null /etc/peart/portal.env
sudo install -o root -g root -m 0600 /dev/null /etc/peart/render.env

O exemplo é deliberadamente recusado pelo validador de configuração: o token de renderização é um placeholder CHANGE_ME, e não há default para o qual ele possa cair em silêncio. Você tem que definir um valor real.

Os três arquivos de ambiente nascem vazios aqui e são preenchidos depois: a página Rodar como serviço diz o que vai em cada um, e a Instalação direta trata do token do renderizador. Eles precisam existir antes de as units subirem, porque cada unit nomeia um com EnvironmentFile= sem traço na frente, então arquivo ausente reprova a unit em vez de ser ignorado.

O que vive em /etc/peart

O diretório em si também não é do root, e os três dígitos de permissão dele são três funções diferentes. O dono é o peart porque alguma coisa nasce aqui dentro: a chave mestra é escrita no primeiro boot por aquele processo, então ele precisa do bit w no diretório, e não só do direito de atravessá-lo. O grupo é o peart-portal porque o portal atravessa, e nada além disso: ele abre o config.yaml pelo caminho inteiro e nunca lista o que mais existe aqui. Outros não recebem nada, então a existência de um master.key neste diretório não é descobrível por uma conta local que não tem o que fazer com essa informação.

Este não é o idioma de travessia-somente que o 0711 do /var/lib/peart usa mais adiante. Lá ninguém escreve na raiz, e o 0711 diz exatamente isso; aqui o dono escreve, e chamar os dois de a mesma coisa seria falso.

O arquivo de configuração não é do root. O peart e o peart-portal rodam como usuários diferentes, com grupos primários diferentes, e os dois o leem, então ele pertence a quem escreve e carrega o grupo de quem lê -- o mesmo idioma, pela mesma razão, do peart.db mais adiante nesta página. Nada para outros, porque o arquivo carrega segredo.

Caminho Dono Grupo Modo Quem lê
config.yaml peart peart-portal 0640 As duas superfícies, cada uma abrindo o arquivo por conta própria: o peart serve como usuário peart, pelos bits de dono, e o peart-portal serve como usuário peart-portal, pelos bits de grupo.
master.key peart peart 0600 Só a superfície interna, como usuário peart. O portal nunca o abre, e a unit dele ainda acrescenta InaccessiblePaths=/etc/peart/master.key por cima.
peart.env root root 0600 O systemd, como root, lendo o EnvironmentFile= ao preparar a unit; os valores chegam ao peart serve como ambiente, então aquele processo nunca abre o arquivo.
portal.env root root 0600 O systemd, do mesmo jeito, para o peart-portal.service.
render.env root root 0600 O systemd, do mesmo jeito, para o peart-render.service; é ele que carrega o token que o sidecar confere em toda requisição.

É isso que deixa os três arquivos de ambiente ficarem root:root 0600 enquanto o config.yaml não pode: eles são lidos pelo PID 1 antes de ele baixar para o User= da unit, e o usuário do serviço nunca precisa enxergá-los. Arquivo que processo nenhum lê não tem o que fazer neste diretório, e é por isso que toda linha da tabela tem um leitor.

O config.yaml não guarda segredo, e a razão está na linha acima dele: o portal lê aquele arquivo. Dois dos campos seriam, sem isso, segredos que a superfície mais exposta consegue ler sem ter uso para eles -- o render.token, que o renderizador confere em toda requisição, e o webhook.secret, a chave HMAC com que a notificação de saída é assinada. Deixe os dois com o placeholder que o exemplo traz e defina PEART_RENDER_TOKEN e PEART_WEBHOOK_SECRET no /etc/peart/peart.env; a página Rodar como serviço diz o que vai em cada arquivo. Os dois sobrescrevem o que o arquivo disser, e variável não definida não sobrescreve nada, então quem guarda os valores no config.yaml continua funcionando; só entrega os dois a um processo que não tem uso para eles.

A regra não é imposta pelo portão, e de propósito: decidir qual campo é segredo exige julgamento, e checagem que exige julgamento deixa de proteger. Ela fica escrita aqui e nos comentários do config.example.yaml, que é onde quem acrescentar um campo vai olhar.

A linha do master.key é o modo que o próprio processo produz, não um que você ajusta: veja a nota abaixo do bloco de permissões, mais adiante.

Caminhos

Todo caminho de dado abaixo já precisa existir e ser gravável pelo usuário peart. O diretório que o master_key_path nomeia também, porque é ali que a chave nasce; o arquivo da chave é a única coisa que não precisa existir, já que o PEART o escreve no primeiro boot se não estiver lá.

db_path: /var/lib/peart/db/peart.db
master_key_path: /etc/peart/master.key
evidence_root: /var/lib/peart/evidence
rendition_root: /var/lib/peart/renditions
report_root: /var/lib/peart/reports
logo_root: /var/lib/peart/logos
avatar_root: /var/lib/peart/avatars
installation_root: /var/lib/peart/installation

master_key_path nunca pode ser igual a, nem ficar dentro de, nenhuma das raízes de dados. O boot recusa uma configuração que a coloque lá, porque a chave nunca pode acabar no mesmo backup que os dados que ela protege.

Dono e modos, para o portal ler o que deve e nada além

As units de systemd já negam ao portal o diretório de evidências e a chave mestra (InaccessiblePaths=), mas isso é uma camada, e vale só enquanto o processo roda sob aquelas units. O sistema de arquivos precisa dizer a mesma coisa por conta própria. Numa instalação bare metal os três usuários são peart, peart-portal e peart-render, criados junto com seus grupos e com o peart-work na página Instalação direta; todo comando abaixo chama essas identidades pelo nome e nenhum deles cria alguma. O processo do portal lê exatamente três coisas: o banco (em leitura e escrita, porque sessões e os registros de auditoria dele passam por uma segunda conexão), as renditions e os relatórios gerados. Ele nunca lê o diretório de evidências nem a chave.

sudo install -d -o peart -g peart        -m 0711 /var/lib/peart
sudo install -d -o peart -g peart-portal -m 2770 /var/lib/peart/db
sudo install -d -o peart -g peart-portal -m 2750 /var/lib/peart/renditions
sudo install -d -o peart -g peart-portal -m 2750 /var/lib/peart/reports
sudo install -d -o peart -g peart        -m 0700 /var/lib/peart/evidence
sudo install -d -o peart -g peart        -m 0700 /var/lib/peart/logos
sudo install -d -o peart -g peart        -m 0700 /var/lib/peart/avatars
sudo install -d -o peart -g peart        -m 0700 /var/lib/peart/installation
sudo install -d -o peart -g peart-work   -m 2750 /var/lib/peart/work

A chave mestra não está nessa lista, e não precisa de nada de você numa instalação nova. O PEART a cria no primeiro boot com criação exclusiva em modo 0600 e logo depois afirma esse modo de novo, para a umask não poder tirar bit nenhum; o processo roda como peart, então o dono já sai certo pelo mesmo motivo. Existe um caso em que você mesmo coloca o arquivo, e é o de restaurar uma chave que você já tinha -- a página Migração de host trata dele, na ordem em que precisa acontecer.

Quatro escolhas aí merecem ser entendidas, e não copiadas.

O 0711 na raiz de dados deixa o portal atravessar para os subdiretórios em que ele pode entrar, sem conseguir listar a raiz. É o idioma de travessia sem leitura, e é por causa dele que o portal nunca precisa ser membro do grupo peart.

O bit setgid (2xxx) nos três diretórios compartilhados faz os arquivos criados ali herdarem o grupo do diretório, então uma rendition escrita pelo peart nasce no grupo peart-portal e continua legível sem ninguém rodar chgrp depois.

O 0700 nas evidências é a linha que mais importa. O portal não está no grupo peart e o diretório não dá nada a outros, então a fronteira se mantém mesmo que o processo seja iniciado à mão, fora do systemd, por um operador depurando alguma coisa às duas da manhã.

O peart-work no diretório de job é o único lugar em que os dois processos se encontram, e só um deles escreve. O peart prepara ali um diretório de job com o HTML do relatório e uma cópia de cada evidência que ele referencia; o peart-render lê esses arquivos, renderiza, e devolve o PDF pela mesma conexão que pediu a renderização. É por isso que o diretório é 2750 e não 2770: o grupo precisa ler e atravessar, nunca escrever, e a unit do renderizador declara este caminho como somente leitura. O bit setgid é o que entrega o grupo compartilhado a cada diretório de job criado aqui, que é o grupo pelo qual ele lê.

As units entregues declaram essa participação por conta própria, com SupplementaryGroups=peart-work no peart.service e no peart-render.service, para que ela fique visível junto com o resto dos direitos do processo e não dependa de um usermod que ninguém audita depois. Nada além disso é compartilhado: o banco, as evidências e a chave continuam fora do alcance do renderizador, e a unit dele segue listando só o diretório de trabalho como gravável.

O arquivo do banco

O peart migrate cria o peart.db, e cria com a umask do processo, o que sob as units entregues resulta num arquivo que o portal lê e não escreve. O portal precisa escrever: sessões e os registros de auditoria dele passam por uma conexão de leitura e escrita. Então, depois da primeira migração, ajuste o arquivo explicitamente:

sudo chown peart:peart-portal /var/lib/peart/db/peart.db
sudo chmod 0660 /var/lib/peart/db/peart.db

Depois suba o portal uma vez e veja o que o SQLite criou ao lado:

ls -l /var/lib/peart/db/

O peart.db-wal e o peart.db-shm também precisam ser graváveis pelo grupo, e vão ser: o SQLite dá aos companheiros o modo do próprio arquivo de banco, ajustando-o de forma explícita para que a umask do processo não possa estreitá-lo. O chmod 0660 acima é, portanto, o passo inteiro, e companheiro com modo errado não é coisa que se conserte no lugar; quer dizer que o banco está com o modo errado, e é lá que se corrige. Chmodar o companheiro parece ter funcionado e depois se desfaz, porque o SQLite apaga os dois companheiros quando a última conexão fecha de forma limpa e os cria de novo, a partir do banco, na abertura seguinte.

O internal/store/db_companion_mode_test.go mede isso em vez de supor, com dois modos de banco diferentes, porque o parágrafo que você está lendo depende dessa medição.

A superfície interna é membro de peart-portal por causa deste diretório, declarado na unit dela como SupplementaryGroups=peart-portal. As duas superfícies abrem o peart.db em modo WAL, e o SQLite cria os dois companheiros quando o primeiro processo abre o banco, removendo ambos quando o último fecha de forma limpa; eles são, portanto, criados de novo a cada boot, por quem tiver chegado primeiro. O setgid deste diretório os põe no grupo peart-portal em qualquer um dos casos. Sem essa filiação, um boot em que o portal abre primeiro deixa companheiros dos quais a superfície interna não é dona nem grupo, e ela não consegue abrir o banco: unable to open database file (14), reiniciando em laço. Nada ordena as duas units, então qual delas abre primeiro é decidido no boot. A filiação não concede nada novo, já que o peart é dono de tudo que está nesse grupo; ela só deixa o processo enxergar o que já possuía.

Endereços de escuta

internal:
  listen_addr: ":8080"
portal:
  listen_addr: ":8081"

Cada binário lê só a sua própria seção.

TLS

tls: true
accept_insecure_http: false

tls: true significa que a instalação fica atrás de um proxy reverso que termina TLS, e liga o cabeçalho Strict-Transport-Security. Deixá-lo false recusa subir a menos que accept_insecure_http também seja true, então uma instalação em HTTP puro é sempre uma decisão explícita. Ver TLS e proxy reverso.

O sidecar de renderização

Para uma instalação systemd ou bare-metal, aponte o renderizador para o endereço de loopback e o diretório de trabalho local, e defina um token compartilhado real:

render:
  base_url: "http://127.0.0.1:8090"
  token: "…"          # openssl rand -hex 32, e o mesmo valor no ambiente do sidecar
  work_root: /var/lib/peart/work
  timeout: 60s

O token é o segredo compartilhado que o sidecar confere em toda requisição; gere com openssl rand -hex 32 e defina o mesmo valor aqui e no PEART_RENDER_TOKEN do sidecar. Os defaults do compose (http://peart-render:8090, /work) só resolvem dentro da rede do container.

Sessões

session:
  inactivity_timeout: 1h
  absolute_timeout: 12h

Os dois podem ser omitidos, e aí caem para uma hora de inatividade e doze horas absolutas. O timeout de inatividade não pode passar de um máximo fixo de quatro horas.

Primeiro acesso

Com a configuração no lugar, suba os serviços (ver Rodar como serviço). No primeiro boot o PEART gera a chave mestra em master_key_path. O primeiro acesso à superfície interna exige criar o administrador e inscrever o TOTP; não existe credencial padrão.