Go to English Blog

Usando 1password-cli para evitar segredos no perfil de seu terminal

Leia em 3 minutos

Uma coisa que sempre me incomodou na configuração de terminal foi adicionar segredos como export GITHUB_TOKEN=<SECRET>. É ainda mais chato quando você tem mais de um computador e precisa sincronizar segredos entre eles.

Eu finalmente decidi lidar com esse problema e para isso vou testar o 1password-cli, um utilitário de linha de comando que permite interagir com o 1Password.

No contexto deste artigo, vou pular a configuração do 1password-cli e vou assumir que o comando op está disponível em seu terminal.

$ which op
/Users/fnando/local/bin/op

O primeiro passo é fazer login com o comando op signin. Quando você terminar, pode listar os seus cofres com o comando op vault ls.

$ op vault ls
ID                            NAME
zyxlrxyu53kax7qqrxz554fgbq    Private
oblww37jzanxpl4wruzjz43i71    dev

No meu caso vou usar o cofre dev para armazenar os segredos que uso em desenvolvimento. Você pode criar o item usando a linha de comando ou a interface do 1Password. Eu vou usar o tipo server para isso:

$ op item create --title main --category server --vault dev
ID:          kbfa7n6hcziy6ck7ys63pzta3a
Title:       main
Vault:       dev (oulww37jzinxpl4wruzjz43i44)
Created:     now
Updated:     now
Favorite:    false
Version:     0
Category:    SERVER
Fields:
  Admin Console:

  Hosting Provider:

Eu recomendo que você abra o 1Password e remova os itens que são adicionados por padrão; infelizmente, eu não achei uma maneira de remover esses itens usando a linha de comando. Aproveite para remover também os campos que foram adicionados por padrão, já que eles não serão usados (senha, usuário e url).

Agora você pode adicionar os segredos usando a o comando op item edit. Se preferir, você também pode usar a interface do 1Password.

$ op item edit --vault dev main 'dev.SOME_API_KEY[password]=SOME_KEY' 'dev.ANOTHER_API_KEY[password]=SOME_OTHER_KEY'
ID:          kbfa7n6hcziy6ck7ys63pzta3a
Title:       main
Vault:       dev (oulww37jzinxpl4wruzjz43i44)
Created:     40 seconds ago
Updated:     now by Nando Vieira
Favorite:    false
Version:     2
Category:    SERVER
Fields:
  dev:
    SOME_API_KEY:       SOME_KEY
    ANOTHER_API_KEY:    SOME_OTHER_KEY

Os segredos acima serão adicionados na seção chamada dev. Aqui tem um screenshot mostrando os segredos no aplicativo do 1Password.

Screenshot do 1Password mostrando os itens que foram criados

Depois que todos os segredos foram adicionados, podemos pegar esses itens em formato JSON usando o comando op item get.

$ op item get --vault dev main --format json
{
  "id": "kbfa7n6hcziy6ck7ys63pzta3a",
  "title": "main",
  "version": 3,
  "vault": {
    "id": "oulww37jzinxpl4wruzjz43i44",
    "name": "dev"
  },
  "category": "SERVER",
  "last_edited_by": "XCFD5SQIJNCZZOF2PBC7XED6QE",
  "created_at": "2022-12-28T08:44:55Z",
  "updated_at": "2022-12-28T00:45:35.033579-08:00",
  "sections": [
    {
      "id": "Section_6r6xfx7vkbniby2fogqg7tvmee",
      "label": "dev"
    }
  ],
  "fields": [
    {
      "id": "notesPlain",
      "type": "STRING",
      "purpose": "NOTES",
      "label": "notesPlain",
      "reference": "op://dev/main/notesPlain"
    },
    {
      "id": "xzuhdgcumcnz5peyvjckq2z4gi",
      "section": {
        "id": "Section_6r6xfx7vkbniby2fogqg7tvmee",
        "label": "dev"
      },
      "type": "CONCEALED",
      "label": "SOME_API_KEY",
      "value": "SOME_KEY",
      "reference": "op://dev/main/dev/SOME_API_KEY"
    },
    {
      "id": "4mg4ejw7q3pnsyworyiflofemq",
      "section": {
        "id": "Section_6r6xfx7vkbniby2fogqg7tvmee",
        "label": "dev"
      },
      "type": "CONCEALED",
      "label": "ANOTHER_API_KEY",
      "value": "SOME_OTHER_KEY",
      "reference": "op://dev/main/dev/ANOTHER_API_KEY"
    }
  ]
}

Note que o 1Password sempre retornará o campo notesPlain, já que ele é nativo e não pode sequer ser removido.

O próximo passo é usar essa lista e convertê-la em um formato que seu terminal entenda. Eu vou usar o jq para essa tarefa.

$ op item get main --vault dev --format json | jq -r '.fields | map(select(has("value"))) | map("export " + .label + "=\"" + .value + "\"") | join("\n")'
export SOME_API_KEY="SOME_KEY"
export ANOTHER_API_KEY="SOME_OTHER_KEY"

Você pode usar o eval com a saída acima, ou pode mandar a saída para um arquivo que pode ser carregado pelo seu terminal. Eu vou usar a segunda opção, mas antes vamos fazer uma limpa e criar um script executável. Vou chamar esse script de op-env.

#!/usr/bin/env bash

set -e

op item get main --vault dev --format json | jq -r '.fields | map(select(has("value"))) | map("export " + .label + "=\"" + .value + "\"") | join("\n")'

Torne esse script executável com o comando chmod +x op-env. Você poderá ver os exports na tela se rodar o comando op-env.

$ op-env
export SOME_API_KEY="SOME_KEY"
export ANOTHER_API_KEY="SOME_OTHER_KEY"

Agora basta adicionar as linhas seguintes ao seu perfil de terminal. Se você usa ZSH, pode usar o arquivo ~/.zshrc. No Bash você pode usar o arquivo ~/.bashrc.

if [ ! -f ~/.op-env ]; then
  op run -- true
  op-env > ~/.op-env
  chmod 600 ~/.op-env
fi

source ~/.op-env

O código acima irá criar um arquivo chamado ~/.op-env a menos que um já exista, permitindo que os segredos fiquem em cache até que este arquivo seja removido ou que você faça a atualização com o comando op-env > ~/.op-env. Essa etapa é necessária porque o 1Password pede autorização primeira chamada do comando op em uma seção de terminal, ou seja, se você abrir uma nova aba, terá que reautorizar o acesso do comando op. Ao fazer cache dos resultados, você precisar fazer isso apenas de vez em quando.

Finalizando

É isso! O 1password-cli permite remover todos os segredos do seu perfil de terminal, sem falar que faz o compartilhamento de segredos uma tarefa muito mais fácil.

E por falar em 1password-cli, aproveite para dar uma olhada no suporte de arquivos .env, que permite o compartilhamento de segredos entre as pessoas do seu time.

Como você lida com este problema? Você usa alguma outra técnica para isso? Compartilhe sua solução nos comentários abaixo.