Programação Por Equipe DevBras

Capa do artigo: docker-mailserver no Git: o que versionar e o que nunca sai do servidor

docker-mailserver no Git: o que versionar e o que nunca sai do servidor

Separe no docker-mailserver o que é configuração pública do que é segredo, tire senha, hash e chave DKIM do repositório e saiba o que trocar se já vazou.

O repositório da infraestrutura tem um commit chamado "subindo o mailserver igual pra todo mundo". Dentro dele, o mailserver.env com a senha do relay, a pasta docker-data/dms/config com o arquivo de contas e a chave DKIM privada do domínio. O repositório é privado, mas já foi clonado em quatro notebooks e numa ferramenta de CI.

A resposta curta: versione a forma, não o conteúdo secreto. O compose.yaml e as opções que ligam e desligam recursos podem ir para o Git. Senhas de relay e de LDAP, o arquivo de contas, as chaves DKIM e os certificados TLS ficam só no servidor, com permissão restrita. Se algum deles já foi commitado, troque o segredo primeiro e limpe o histórico depois.

Por que o compose de exemplo vira vazamento

A documentação do docker-mailserver lista dezenas de variáveis de ambiente, e quase todas são inofensivas: ligar antispam, escolher o tipo de certificado, definir o endereço do postmaster. Por isso dá vontade de tratar o arquivo inteiro como configuração pública. Só que algumas variáveis carregam credencial, como as de usuário e senha do relay e a senha de bind do LDAP. Confira os nomes exatos na página de ambiente da versão que você roda, porque eles mudam entre versões.

O maior risco, porém, não é o .env. É a pasta de configuração montada no container. Ali o comando setup grava o arquivo de contas, com o hash das senhas das caixas, e as chaves DKIM privadas. Quem tem a chave DKIM assina mensagem como se fosse o seu domínio, e ela passa na verificação. Quem tem o hash pode tentar quebrar as senhas fora do seu servidor, no tempo dele.

Repositório privado não é cofre. Ele é copiado para cada máquina que clona, para backups, forks e ferramentas de integração. A regra geral está em segredo não entra na imagem do container; aqui ela é aplicada ao servidor de e-mail.

O que versionar e o que não versionar

O exemplo: o servidor mail.lojaexemplo.com.br, em docker-mailserver, com envio de saída por relay.

  • Vai para o Git: compose.yaml, mailserver.env só com opções sem segredo, um mailserver.secrets.env.example com os nomes das variáveis e valores vazios, e a documentação de como gerar contas e chaves.
  • Fica só no servidor: mailserver.secrets.env, toda a pasta docker-data/ (contas, chaves DKIM, caixas, estado, logs) e os certificados TLS.

Como organizar o repositório, passo a passo

  1. Divida o ambiente em dois arquivos: um público e um secreto.
  2. Carregue os dois no compose com env_file em lista.
  3. Ignore no Git o arquivo secreto e a pasta de dados antes do primeiro commit.
  4. Crie o arquivo secreto no servidor, com permissão 600 e dono restrito.
  5. Crie as contas e as chaves no servidor, com o setup do próprio container, e faça backup dessa pasta por um canal separado.
  6. Use uma conta própria para o aplicativo, como noreply@, nunca a conta do administrador ou do postmaster.

O compose com dois arquivos de ambiente

# compose.yaml
services:
  mailserver:
    image: ghcr.io/docker-mailserver/docker-mailserver:14.0.0
    container_name: mailserver
    hostname: mail.lojaexemplo.com.br
    env_file:
      - mailserver.env
      - mailserver.secrets.env
    ports:
      - "25:25"
      - "465:465"
      - "587:587"
      - "993:993"
    volumes:
      - ./docker-data/dms/mail-data/:/var/mail/
      - ./docker-data/dms/mail-state/:/var/mail-state/
      - ./docker-data/dms/mail-logs/:/var/log/mail/
      - ./docker-data/dms/config/:/tmp/docker-mailserver/
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - /etc/localtime:/etc/localtime:ro
    restart: always

Fixe a versão da imagem que você testou, em vez de latest; o motivo está em a tag latest mente. Os certificados vêm do host, somente leitura, e nunca passam pelo repositório.

O .gitignore e o arquivo de exemplo

# .gitignore
docker-data/
mailserver.secrets.env

# mailserver.secrets.env.example (este vai para o Git, sem valores)
# Copie para mailserver.secrets.env no servidor e preencha.
# Confira os nomes na documentação da versão em uso.
RELAY_USER=
RELAY_PASSWORD=
# no servidor
cp mailserver.secrets.env.example mailserver.secrets.env
chmod 600 mailserver.secrets.env
docker compose up -d
docker exec -it mailserver setup email add noreply@lojaexemplo.com.br
docker exec -it mailserver setup config dkim

Sem a senha na linha de comando, o setup email add pede a senha de forma interativa, e ela não fica no histórico do shell. O comando de DKIM grava a chave privada dentro de docker-data/dms/config e mostra o registro TXT que você publica no DNS. Só a parte pública vai para o DNS; a privada não sai do servidor.

Como descobrir se já vazou

git ls-files | grep -E "docker-data|secrets.env|postfix-accounts|\.private$"
git log --all --oneline -- docker-data mailserver.env mailserver.secrets.env
git log --all -p -S "RELAY_PASSWORD" -- mailserver.env

O primeiro comando mostra o que está rastreado hoje. Os outros dois procuram no histórico inteiro, inclusive em branches. Se algo aparecer, considere o segredo comprometido, mesmo que o arquivo tenha sido apagado num commit posterior. Ferramentas como o gitleaks ajudam a automatizar essa busca no pre-commit e na CI.

O que trocar, e em que ordem

  1. Senha do relay: gere uma nova credencial no provedor de envio, atualize o arquivo secreto, reinicie o container e só então revogue a antiga.
  2. Senhas das caixas: troque com setup email update para cada conta exposta e avise os usuários.
  3. Chave DKIM: gere uma chave com seletor novo, publique o TXT do novo seletor, passe a assinar com ele e remova o registro antigo do DNS depois de alguns dias. Removendo antes, mensagens em trânsito falham na verificação.
  4. Só depois limpe o histórico e tire os arquivos do índice com git rm -r --cached.

A lógica de aceitar o antigo e o novo por um tempo está em trocar segredo sem derrubar o sistema, e o porquê da ordem está em segredo no Git: troque a chave antes de limpar o histórico.

Erros comuns

  • Commitar o .env "para o time subir igual". A senha do relay passa a existir em todo notebook que clonou, para sempre no histórico.
  • Versionar a pasta docker-data. Vão junto o hash das senhas e a chave DKIM, que permite assinar mensagens falsas em nome do domínio.
  • Limpar o histórico sem trocar o segredo. As cópias já clonadas continuam com o valor válido.
  • Usar a conta do administrador como remetente do aplicativo. Um vazamento da credencial do app entrega a caixa mais sensível do domínio.
  • Desligar verificações para "entregar de qualquer jeito". Desativar TLS no relay ou relaxar restrições de envio troca um problema de configuração por um servidor inseguro.
  • Remover o seletor DKIM antigo no mesmo minuto da troca. Mensagens já assinadas e ainda na fila falham na verificação do destinatário.

Checklist

  • git ls-files não lista docker-data, arquivo secreto, contas ou chave privada.
  • O histórico não tem senha de relay nem chave DKIM.
  • O arquivo secreto no servidor tem permissão 600.
  • O repositório tem um arquivo de exemplo com os nomes das variáveis, sem valores.
  • A imagem está fixada numa versão testada.
  • O aplicativo envia por uma conta própria, não pela do administrador.
  • A pasta de configuração tem backup fora do Git.

Rode git log --all -p -S "PASSWORD" no repositório da sua infraestrutura agora: ele mostra alguma senha ou chave privada de e-mail?

Avalie este artigo

Referência: https://docker-mailserver.github.io/docker-mailserver/edge/config/environment/