Kamal e 1Password: Um Fluxo De Deploy De Secrets Mais Seguro

A melhor parte do Kamal é que ele faz o deploy parecer menor. Menos cerimonial, menos overhead de plataforma e menos "vamos agendar um horário de infra na semana que vem".

É por isso que a manipulação de secrets merece atenção extra.

Quando os deploys ficam mais fáceis, torna-se tentador manter alguns valores flutuando em sessões de shell, configurações de CI ou trechos copiados, porque tudo continua funcionando. E, por um tempo, funciona.

Se você já está fazendo deploy com o Kamal, as chances são de que seus secrets viajem por meio de variáveis de ambiente. Algo como DB_PASSWORD=$DB_PASSWORD em .kamal/secrets é muito melhor do que colocar credenciais fixas em um arquivo commitado. Mas isso ainda deixa uma pergunta silenciosa: onde esse valor reside antes do Kamal recebê-lo, quem pode buscá-lo e quanto do seu caminho de deploy precisa tocá-lo?

Este post mostrará como substituir esse fluxo solto por uma configuração mais segura, apoiada pelo 1Password, sem transformar o deploy novamente em uma missão secundária de DevOps.

Estado atual vs estado 1Password: secrets espalhados e confusão à esquerda, um pipeline limpo do cofre para o deployment à direita

Antes que comece

Se você é novo no Kamal, comece com meu vídeo, 30 Minutes Deploy with Kamal – No DevOps Required. Ele cobre as partes mais relevantes do Kamal, desde a configuração inicial até ter ambientes de produção e staging.

Observe também que o Kamal não está preso a um único gerenciador de secrets. Seus adaptadores de secrets documentados incluem 1Password, Bitwarden, Bitwarden Secrets Manager, LastPass, AWS Secrets Manager, GCP Secret Manager, Doppler e Passbolt.

Vou usar o 1Password nos exemplos porque as empresas costumam escolhê-lo como seu gerenciador de senhas. A estrutura da solução é semelhante à de outras ferramentas, porém: o Kamal continua sendo a ferramenta de deploy, o gerenciador de secrets torna-se a fonte da verdade e seu ambiente de deploy recupera apenas o que precisa.

Uma exceção importante antes de prosseguirmos: se você está armazenando secrets reais em texto simples diretamente no .kamal/secrets, pare de fazer isso imediatamente. Rotacione esses secrets, limpe o arquivo e volte para a manipulação baseada em variáveis de ambiente antes de seguir qualquer outra coisa neste guia.

O Que o Kamal Já Faz Bem

De acordo com a documentação oficial, as variáveis de ambiente podem vir entweder diretamente da sua configuração do Kamal ou do .kamal/secrets. Esse arquivo usa dotenv, suporta substituição de variáveis, suporta substituição de comandos e pode chamar helpers de secrets. O Kamal também distingue entre valores clear e secret sob env, e a parte sutil aqui é importante: valores secretos não são passados diretamente para docker run. O Kamal os armazena em um arquivo env no host.

Isso significa que a base comum já se parece com isto:

# .kamal/secrets
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
DB_PASSWORD=$DB_PASSWORD
# config/deploy.yml
env:
  clear:
    APP_ENV: production
  secret:
    - KAMAL_REGISTRY_PASSWORD
    - DB_PASSWORD

Na verdade, esse é o ponto de partida correto para muitas equipes. O problema é que esse padrão não diz nada sobre de onde o DB_PASSWORD veio ou por quanto tempo ele permanece em um shell. Ele não informa se veio de uma conta pessoal, se o seu runner de CI consegue ler muito mais do que deveria, ou se o mesmo caminho de busca existe para staging, produção e depuração local. Esse é o verdadeiro gap de segurança.

O Kamal também suporta arquivos de secrets específicos para cada destino. Se você faz deploy tanto para staging quanto para produção, pode dividir os secrets entre .kamal/secrets.staging e .kamal/secrets.production, com .kamal/secrets-common

para valores compartilhados por ambos. Essa estrutura combina bem com a abordagem de cofre por ambiente descrita mais adiante. ## As Variáveis de Ambiente Permanecem, a Origem Muda

Containers ainda precisam de variáveis de ambiente, e isso não é problema. O que muda é a frequência com que um segredo é materializado, quem pode disparar isso e a facilidade de auditar e revogar o acesso. Quando um segredo precisa mudar, você o rotaciona no 1Password e faz o redeploy. Sem atualizações de configuração de CI, sem procurar qual perfil de shell tem o valor antigo, sem mensagens no Slack perguntando "alguém tem a nova senha do DB?".

O Que Você Precisa Configurar No 1Password Primeiro

Antes de mexer no .kamal/secrets, configure o lado do 1Password corretamente.

  1. Crie um cofre dedicado para a aplicação e o ambiente que você está deployando, pois cofres separados tornam muito mais fácil gerenciar quem tem acesso a cada ambiente.
  2. Crie um item de Nota Segura nesse cofre e adicione um novo campo para cada variável de ambiente que o Kamal precisa, como REGISTRY_PASSWORD e DB_PASSWORD. Outros tipos de itens também podem funcionar, mas Nota Segura geralmente é a opção mais flexível aqui.
  3. Crie uma conta de serviço do 1Password com acesso apenas aos vaults que o deployment realmente precisa.
  4. Instale a CLI do 1Password na máquina que executará o kamal deploy.
  5. Autentique essa CLI com a conta de serviço em vez de uma conta pessoal.
  6. Verifique se a máquina consegue ler o item esperado antes de adicionar a integração do Kamal por cima.

    op item get "Env" --vault "Production"
    ID:          123456789
    Title:       Env
    Vault:       Production
    Created:     55 minutes ago
    Updated:     6 seconds ago by Alexandre
    Favorite:    false
    Version:     3
    Category:    SECURE_NOTE
    Fields:
    notesPlain:           API Production Environment Variables 
    DB_PASSWORD:          [use 'op item get 123456789 --reveal' to reveal]
    REGISTRY_PASSWORD:    [use 'op item get 123456789 --reveal' to reveal]

A parte da conta de serviço merece um olhar mais atento. A documentação de contas de serviço do 1Password é clara aqui: contas de serviço existem para ambientes compartilhados e automação, e você pode restringi-las a cofres e Ambientes específicos. Elas também oferecem um limite de automação muito mais limpo do que vincular o acesso de implantação a uma conta humana.

Isso é importante porque as implantações do Kamal geralmente acontecem em locais onde a proliferação de acessos se torna normalizada:

  • runners de CI
  • terminais de longa duração
  • scripts que todos copiaram da mesma página da wiki três anos atrás

Se o comando que executa kamal deploy se autenticar no 1Password com uma conta de serviço, você pode reduzir drasticamente o raio de impacto. O caminho de implantação precisa apenas de acesso aos cofres necessários para aquele aplicativo e aquele ambiente. Não a sua conta inteira do 1Password. Não ao acesso do cofre pessoal de um engenheiro aleatório. Apenas os secrets de implantação.

Uma única conta de serviço com acesso de leitura restrito aos cofres de Production, Staging e Development

O 1Password também documenta OP_SERVICE_ACCOUNT_TOKEN como a variável de ambiente usada para autenticar a CLI com uma conta de serviço. Isso oferece um caminho de automação claro para CI ou hosts de implantação dedicados.

Use o Adaptador Nativo do 1Password do Kamal

Na prática, a opção mais limpa é deixar o .kamal/secrets buscar do 1Password diretamente.

O Kamal envia um comando kamal secrets com um adaptador nativo 1password. O padrão é simples: busque o conjunto de secrets uma vez e depois extraia os valores individuais que você precisa:

# .kamal/secrets
SECRETS=$(kamal secrets fetch --adapter 1password --account myaccount --from Production/Env REGISTRY_PASSWORD DB_PASSWORD)

KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract REGISTRY_PASSWORD $SECRETS)
DB_PASSWORD=$(kamal secrets extract DB_PASSWORD $SECRETS)

Secrets fluem de um cofre centralizado do 1Password para o Kamal via uma busca controlada, substituindo exportações de shell dispersas e arquivos de configuração de CI

No geral, isso é uma melhoria significativa em relação à exportação manual de valores de longa duração no seu perfil de shell ou configurações de CI.

Aqui está o porquê:

  • O 1Password torna-se a fonte da verdade em vez de um humano copiando secrets por aí.
  • O Kamal ainda recebe as variáveis de ambiente que espera.
  • Você reduz a chance de secrets obsoletos viverem para sempre em uma sessão de shell ou em um aplicativo de notas em algum lugar.
  • A lógica de busca e extração permanece próxima da ferramenta de implantação que realmente precisa dos valores.

1Password Melhora a Fonte da Verdade

O Kamal ainda materializa variáveis de ambiente para o alvo da implantação. Como os próprios documentos do 1Password alertam, você deve assumir que processos executados como o mesmo usuário podem ler o ambiente uns dos outros. Portanto, as variáveis de ambiente não se tornam subitamente mais seguras apenas porque o 1Password está na jogada. O que melhora é o sistema que produz os valores e a disciplina do caminho que os busca.

Se o seu host de implantação for desorganizado, o 1Password não salvará você disso. Você ainda precisa se preocupar com:

  • quem pode fazer login na máquina de implantação
  • quem pode inspecionar ambientes de processos
  • o que vai para o histórico do shell
  • o que é exibido na saída de depuração
  • o que seus logs de CI guardam para sempre

É por isso também que contas de serviço e escopo de processos importam tanto. A verdadeira vitória não é que os segredos residam no 1Password, mas que menos atores possam fazer com que eles saiam de lá, para começar.

Cuidado Se Você Executa o Kamal Via Docker

O modo Dockerized do Kamal altera a questão dos segredos de uma maneira importante. Os adaptadores de segredo não funcionam dentro do container porque as CLIs do secret-manager não estão instaladas lá. Variáveis de ambiente do host também ficam indisponíveis, a menos que você as injete explicitamente.

Se a sua configuração depende do adaptador do 1Password, use uma instalação normal do Kamal na máquina que executa os deploys. Para casos onde o Kamal Dockerized é um requisito obrigatório, você pode buscar os segredos fora do container primeiro e passá-los via flags -e no alias do Docker. No entanto, isso desloca o limite de confiança de volta para o shell do host e remove a maioria dos benefícios do adaptador.

Aprofundando: Fazendo Isso Funcionar em CI/CD

Além dos deploys locais, a mesma configuração baseada em adaptadores também funciona bem em CI/CD. Aqui está um exemplo do GitHub Actions que mostra as partes principais:

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
    steps:
      - uses: actions/checkout@v4

      - name: Install 1Password CLI
        uses: 1password/install-cli-action@v2

      - name: Set up Ruby and install Kamal
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.4.8"
      - run: gem install kamal

      - name: Set up SSH key
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Deploy
        run: kamal deploy

Os únicos segredos armazenados no GitHub são OP_SERVICE_ACCOUNT_TOKEN e a chave SSH para alcançar o destino do deploy. Todo o restante vem do 1Password no momento do deploy através da mesma configuração de adaptador .kamal/secrets que você usa localmente. O Kamal é instalado via Ruby, não pelo alias do Docker, então o adaptador do 1Password realmente funciona.

O padrão é semelhante no GitLab CI, CircleCI ou Buildkite: instale a CLI do 1Password, exponha o token da conta de serviço, instale o Kamal nativamente e faça o deploy.

Conclusão

No fim das contas, usar bem o 1Password em um fluxo de trabalho do Kamal não adiciona burocracia corporativa. Ele mantém a simplicidade enquanto aperta o limite em torno da única coisa que você não quer vazar.

O adaptador oferece um padrão único de busca e extração que funciona da mesma maneira localmente e em CI. Como resultado, os segredos ficam em um só lugar, o acesso é limitado ao que cada ambiente realmente precisa, e rotacionar uma credencial significa alterá-la no 1Password e fazer o redeploy.

Mantenha o fluxo de trabalho de variáveis de ambiente. Apenas pare de tratar a máquina que o inicia como um balde cheio de segredos de longa duração.

We want to work with you. Check out our Services page!