Secrets e Encriptacao
O Runner implementa um sistema de encriptacao em duas camadas para proteger secrets e permitir recuperacao completa em caso de perda do servidor.
Nota v2.12.0+: o
--branchagora e obrigatorio emrunner add. Os exemplos abaixo usam--branch distpor convencao mas sirva sempre o branch real do repo (main,dev, etc). O--ckeysem valor (ex:runner add --repo X --branch main --ckey) gera ckey random de 32 chars automaticamente — guarde no password manager (mostrado uma unica vez no stderr).Nota v2.14.0+: o runner agora BLOQUEIA
runner addse detectar key sensitive (DB_PASSWORD,API_KEY,JWT_SECRET, etc) emenvironment:sem ckey configurada. Mover prasecrets:no.deploy.ymlou adicionar--ckey. Bypass via `--insecure` (NAO RECOMENDADO).
Problema
Quando um servidor de producao morre, voce perde:
- Arquivos
.enve.secretsde cada aplicacao - Configuracoes manuais (API keys, senhas externas)
- Estado das aplicacoes
Reconstruir tudo manualmente e lento e propenso a erros.
Solucao: Encriptacao em Duas Camadas
Camada 1: ckey (por projeto) Camada 2: master key (por servidor)
+---------------------------+ +-----------------------------+
| Fornecida pelo usuario | | Auto-gerada no runner init |
| via: runner add --ckey | | Efemera (morre com server) |
| | | |
| Encripta: .env + .secrets | | Encripta: ckeys em repouso |
| Destino: .runner/ | | no state file |
| secrets.enc (no repo) | | |
| | | Servidor morre -> |
| Usuario memoriza/salva | | gera nova master key, |
| em password manager | | user re-passa as ckeys |
+---------------------------+ +-----------------------------+Master Key
- Gerada automaticamente pelo
runner init - Armazenada em
/opt/runner/.keys/master.key(permissao 600) - Usada para encriptar ckeys e tokens no state file
- Efemera: se o servidor morre, uma nova e gerada
- Nao precisa ser memorizada pelo usuario
Master Key Backup (v2.8.0+)
Para disaster recovery, exporte a master key antes de perder o servidor:
runner mkey reveal --json # mostra mkey + fingerprint + created_at + rotated_count
runner mkey export --sealed --json # blob mkseal:v1:... pra storage offlineInjete numa nova instalacao:
runner init --mkey "BASE64_DA_MASTER_KEY"Master Key Rotation (v2.11.0+)
Rotacionar a master key re-sela todas as ckeys atomicamente:
runner mkey rotate --force --json
# {
# "old_fingerprint": "mk_2c1a…b87f",
# "new_fingerprint": "mk_9001…3f0a",
# "ckeys_resealed": 4,
# "duration_ms": 1820,
# "backup_path": "/opt/runner/.keys/master.key.rotated.2026-04-25T....bak"
# }Usar quando suspeitar de comprometimento da mkey atual ou em rotação periodica de seguranca.
Content Key (ckey)
- Fornecida pelo usuario ao registrar uma app (
runner add --ckey) - Usada para encriptar
.enve.secretsdo projeto - O resultado e salvo como
.runner/secrets.encdentro do repositorio - Persistente: o usuario deve salvar em um password manager
- Mesma ckey restaura os secrets em qualquer servidor
Display de ckey gerada (v2.18.0+)
Por default, runner add --ckey (sem valor) gera ckey random e mostra apenas o fingerprint:
Generated random ckey (fingerprint: ck_XEpj…JRLx).
Stored encrypted in /opt/runner/state/<app>.yml.
Retrieve later: `runner ckeys export <app>` (with mkey).
Display plaintext: rerun with --ckey-show (only on private terminals).A ckey fica encriptada em repouso com a mkey local (state file mode 600). Pra recuperar plaintext: runner ckeys export <app>.
Pra exibir plaintext ao gerar (ex: pra colar no password manager imediatamente), use --ckey-show:
runner add --repo X --branch main --ckey --ckey-show
# Generated random ckey (32 chars). Save it now: shown only here.
# ckey: <32-char-alfanum-aleatoria> # exemplo: XEpjzTTA…JRLx (seu valor sera diferente)
# fingerprint: ck_XEpj…JRLxJustificativa: terminal compartilhado, log de CI, paste em chat/issue eram vetores de leak antes da v2.18.0. Default agora protege.
Env Wizard (v2.8.1+)
Os arquivos .env e .secrets podem ser gerados automaticamente a partir das secoes environment: e secrets: do .deploy.yml, sem depender de templates separados.
Veja Env Wizard para sintaxe completa e exemplos.
Wizard CLI (v2.17.0+) — gerar `.secrets.enc` standalone
Voce pode gerar .runner/secrets.enc antes mesmo de instalar o runner usando o subcomando runner wizard. O wizard:
- Detecta variaveis sensiveis em
.env/.env.example/docker-compose.yml - Pergunta o que fazer com cada uma (manter, editar, marcar como secret, remover)
- Gera ckey random (ou aceita uma sua) e encripta em
.runner/secrets.enc - Mostra a ckey uma unica vez — anote
- Comita junto com
.deploy.ymlno repo
runner wizard --path /caminho/repo --ckey # gera ckey random
runner wizard --path . --ckey "minha-ckey" # usa ckey existenteNo deploy, basta passar a mesma ckey:
runner add --repo user/app --branch main --ckey "minha-ckey"
# Runner detecta .runner/secrets.enc no repo e restaura .env + .secretsDetalhes: `runner wizard`.
Vault (v2.11.0+)
Listar e gerenciar ckeys
runner ckeys list --json # enumera ckeys (per-app + shared)
runner ckeys add <project> --algorithm AES-256-GCM # cria ckey shared selada com mkey
runner ckeys export <id> --json # exporta ckey selada (transferivel entre servers com mesma mkey)
runner ckeys import-sealed --blob <b64> --project <p> # importa ckey de outro serverConfig Backups
Snapshots automaticos de .deploy.yml + .secrets.enc + state.yml por app:
runner config-backups list --json
runner config-backups create <app> --json # snapshot manual
runner config-backups restore <id> --json # restaura (auto pre-restore snapshot)Cross-project secrets
# Local (mesmo server)
runner secrets paste-encoded --project hogi --key DB_PASS --mode manual --value xxx
runner secrets copy --from inboxer --to hogi --keys SMTP_HOST,SMTP_PASS
# Cross-server (sys orquestra via export/import-sealed)
runner secrets export --project hogi --keys SMTP_PASS,DB_URL --json
# → blob secseal:v1:... pra import em outro server com mesma mkey
runner secrets import-sealed --blob <secseal> --project hogi --jsonBug Resolvido (v2.11.2)
A versao v2.4.2 ate v2.11.1 tinha um bug onde o .secrets nao era injetado em redeploys
se o state.ckey da app estivesse ausente (perdido em migracao, removido manualmente, etc).
Resultado: containers subiam com credenciais vazias e workers falhavam ao bootar.
A v2.11.2 remove a verificacao app_has_ckey — agora o .secrets e sempre injetado se o
arquivo existir. Atualize com runner self-update se voce esta em uma versao afetada.
Fluxo Completo
Primeiro Deploy (Setup)
# 1. Inicializar Runner (gera master key)
runner init
# 2. Registrar app com ckey
runner add \
--repo devborlot/minha-app \
--branch dist \
--token ghp_xxxxxxxxx \
--ckey "minha-chave-secreta-do-projeto"
# 3. Fazer deploy (provisiona .env/.secrets, encripta e commita no repo)
runner deploy minha-appApos o deploy, o Runner:
- Provisiona
.enve.secretsa partir de.env.template - Encripta ambos com a ckey usando AES-256-GCM
- Salva como
.runner/secrets.encno repositorio - Commita e faz push automaticamente
Deploys Seguintes
runner deploy minha-appA cada deploy, os secrets sao re-encriptados e atualizados no repo. Se voce alterar uma variavel via runner env set, o proximo deploy atualiza o secrets.enc.
Recovery (Servidor Morre)
# 1. Inicializar Runner no novo servidor (nova master key)
runner init
# 2. Registrar app com a MESMA ckey
runner add \
--repo devborlot/minha-app \
--branch dist \
--token ghp_xxxxxxxxx \
--ckey "minha-chave-secreta-do-projeto"
# 3. Runner detecta .runner/secrets.enc no repo e restaura .env/.secrets
# 4. Deploy funciona sem intervencao manual
runner deploy minha-appO runner add --ckey detecta automaticamente se .runner/secrets.enc existe no repo e, se .env/.secrets nao existem localmente, restaura-os usando a ckey.
Regra de Encriptacao (v2.4.2)
O .secrets so existe com encriptacao. Sem --ckey, nao ha .secrets — tudo vai pro .env.
| Registro | .secrets |
Comportamento |
|---|---|---|
runner add --repo X --ckey K |
Criado (chmod 600) | Encriptado em repouso |
runner add --repo X (sem ckey) |
Nao criado | Secrets vao pro .env |
Deteccao automatica
O runner detecta automaticamente variaveis sensiveis pelo nome (Aho-Corasick, v2.4.2):
- Alta confianca (95%+):
DB_PASSWORD,API_KEY,GITHUB_TOKEN→ com ckey, encripta automaticamente. Sem ckey, salva no.envcom warning - Media confianca (75%):
MY_TOKEN,APP_SECRET→ aviso "pode ser sensivel" - Falsos positivos filtrados:
keyboard,primary_key,max_tokens,cache_key,public_key
Forcando como secret
runner env set myapp --key CUSTOM --value xxx --secret # requer ckey
runner env set myapp --key CUSTOM --value xxx --force # requer ckey, sem questionamentoSem ckey, --secret e --force retornam erro: "Secrets requerem encriptacao. Registre com --ckey".
Detalhes Tecnicos
Algoritmo de Encriptacao
| Componente | Algoritmo |
|---|---|
| Derivacao de chave | SHA-256 (ckey -> chave AES) |
| Encriptacao | AES-256-GCM |
| Nonce | 12 bytes aleatorios |
| Formato | nonce (12 bytes) + ciphertext |
Formato do secrets.enc
O arquivo .runner/secrets.enc contem:
[12 bytes nonce][ciphertext AES-256-GCM]Ao decriptar, o conteudo e:
---ENV---
CHAVE1=valor1
CHAVE2=valor2
---SECRETS---
SECRET_KEY=valor_secreto
DB_PASSWORD=senhaPermissoes de Arquivos
| Arquivo | Permissao | Motivo |
|---|---|---|
.env |
644 | Configuracao nao sensivel |
.secrets |
600 | Credenciais sensiveis |
master.key |
600 | Chave mestra do servidor |
secrets.enc |
Repo | Seguro (encriptado) |
Estrutura no Repositorio
minha-app/
├── .deploy.yml
├── .env.template
├── .runner/
│ └── secrets.enc # Encriptado com ckey
├── dist/
│ └── ...
└── package.jsonO .runner/secrets.enc e versionado no repositorio. O Runner garante que nao esta no .gitignore adicionando uma regra de negacao se necessario.
State File
A ckey e armazenada encriptada no state file (/opt/runner/state/{app}.yml):
app_path: /data/apps/minha-app
project: minha-app
ckey: "enc:base64_nonce:base64_ciphertext" # Encriptada com master key
github_token: "enc:base64_nonce:base64_ciphertext"Seguranca
O que e seguro
- A ckey nunca e armazenada em texto plano no disco
- Os secrets no repo estao encriptados com AES-256-GCM
- A master key tem permissao 600 (somente root/runner)
- Sem a ckey,
secrets.ence ilegivel
Recomendacoes
- Use ckeys fortes: minimo 16 caracteres, alfanumericos + especiais
- Salve ckeys em password manager: 1Password, Bitwarden, etc.
- Uma ckey por projeto: nao reutilize entre projetos
- Nao commite ckeys: nunca coloque a ckey em
.deploy.ymlou codigo
O que acontece se...
| Cenario | Resultado |
|---|---|
| Servidor morre | Novo runner init + runner add --ckey restaura tudo |
| Esqueceu a ckey | Secrets perdidos. Reconfigure manualmente |
| Repo comprometido | Atacante ve secrets.enc mas precisa da ckey para decriptar |
| Master key comprometida | Atacante ve ckeys nos state files. Rotacione ckeys |
Boas Praticas
Para Novos Projetos
# Gerar ckey forte
openssl rand -base64 32
# Resultado: dG9wX3NlY3JldF9rZXlfMTIzNDU2Nzg5...
# Salvar no password manager ANTES de usar
# Depois:
runner add --repo devborlot/meu-app --branch main --ckey "dG9wX3NlY3JldF9rZXlfMTIzNDU2Nzg5..."Para Projetos Existentes
Se ja tem uma app registrada sem ckey, adicione usando runner edit:
# Editar para adicionar ckey (futuro - use re-add por enquanto)
# Remova e re-adicione a app com --ckeyDocumentacao de ckeys
Mantenha um registro das ckeys em local seguro:
Projeto: minha-app
Repo: devborlot/minha-app
ckey: dG9wX3NlY3JldF9rZXlfMTIzNDU2Nzg5...
Criada em: 2026-03-11Deploy All
O comando deploy --all permite deployar todas as apps registradas de uma vez:
runner deploy --allUtil apos recovery do servidor:
# 1. Re-registrar todas as apps com suas ckeys (--branch obrigatorio v2.12.0+)
runner add --repo devborlot/app1 --branch main --ckey "ckey1" --token ghp_xxx
runner add --repo devborlot/app2 --branch main --ckey "ckey2" --token ghp_xxx
runner add --repo devborlot/app3 --branch dev --ckey "ckey3" --token ghp_xxx
# 2. Deployar todas de uma vez
runner deploy --allO comando itera todos os state files em /opt/runner/state/ e executa deploy para cada app.
Opcoes
runner deploy --all # Deploy todas as apps
runner deploy --all --force # Forca redeploy de todas
runner deploy --all --verbose # Output detalhadoNetwork Auto-Creation
O Runner agora cria automaticamente networks Docker que nao existem. Se o .deploy.yml configura networks: [public, mysql, redis] e a network mysql nao existe, o Runner a cria antes de iniciar o container.
Alem disso, o Runner emite warnings quando uma network nao-publica esta vazia (sem containers), indicando que a infraestrutura pode nao estar rodando:
WARN: Network 'mysql' has no containers. minha-app may not connect to mysql.Troubleshooting
Secrets nao restaurados no add
# Verificar se secrets.enc existe no repo
ls /data/apps/minha-app/.runner/secrets.enc
# Verificar se .env ja existe (restauracao so ocorre se .env NAO existe)
ls /data/apps/minha-app/.envDecriptacao falha
A ckey esta incorreta. Verifique:
# Tentar com ckey correta
runner add --repo devborlot/minha-app --branch main --ckey "ckey-correta"secrets.enc nao atualizado no repo
Verifique se o git push funciona:
cd /data/apps/minha-app
git remote -v
git statusO Runner faz git add .runner/secrets.enc && git commit && git push. Se falhar, um warning e emitido mas o deploy continua.