Pular para o conteúdo principal

Chaves a partir de variáveis de ambiente e arquivos

Além de armazenar um segredo no banco de dados, uma entrada do Armazenamento de Chaves pode ler seu valor no momento da tarefa a partir de um arquivo no servidor Semaphore ou de uma variável de ambiente do processo do servidor Semaphore. Isso é útil quando a credencial já é provisionada fora do Semaphore, por exemplo:

  • uma chave SSH montada no contêiner do Semaphore como um secret do Docker ou do Kubernetes;
  • um token gravado em disco por um agente (HashiCorp Vault Agent, cert-manager etc.) e rotacionado regularmente;
  • uma senha injetada no ambiente do contêiner pelo seu orquestrador.

O Semaphore não copia o valor para o seu banco de dados. Sempre que uma tarefa precisa da chave, o servidor lê o arquivo ou a variável novamente, de modo que rotacionar a credencial no disco tem efeito na próxima tarefa.

info

O arquivo ou a variável é lido pelo servidor Semaphore, não por um runner. Quando você usa runners remotos, monte o arquivo no host do servidor; o servidor resolve o segredo e o entrega ao runner.

Escolhendo a origem

Ao criar ou editar uma chave (Armazenamento de Chaves → Nova Chave), a parte superior do formulário tem abas de origem:

AbaDe onde vem o valorO que informar
LocalBanco de dados do Semaphore (criptografado)O login, a senha ou a chave privada no formulário
Storage ProArmazenamento de segredos externo, como o HashiCorp VaultO armazenamento e o caminho do segredo
EnvUma variável de ambiente do processo do servidor SemaphoreO nome da variável, por exemplo PROD_SSH_KEY
FileUm arquivo no servidor SemaphoreO caminho absoluto do arquivo, por exemplo /var/lib/semaphore/secrets/prod.json

Com Env ou File selecionado, os campos de login, senha e chave privada desaparecem. A credencial completa, incluindo o login para chaves SSH e Login com Senha, deve estar no arquivo ou na variável.

1. Permitir o diretório

Por segurança, o Semaphore só lê arquivos de chave que estejam dentro do seu diretório de segredos. Qualquer outro caminho é rejeitado quando uma tarefa é iniciada:

Failed to install inventory: file path must be inside secrets path

O diretório de segredos padrão é /tmp/semaphore. Aponte-o para o diretório onde seus arquivos de chave estão usando dirs.secrets no config.json ou a variável de ambiente SEMAPHORE_SECRETS_PATH. Consulte Diretório de segredos para as regras de precedência.

Exemplo de Docker Compose que monta um diretório do host e o permite:

services:
semaphore:
image: semaphoreui/semaphore:latest
environment:
SEMAPHORE_SECRETS_PATH: /var/lib/semaphore/secrets
volumes:
- /srv/semaphore/secrets:/var/lib/semaphore/secrets:ro

Fragmento equivalente de config.json:

{
"dirs": {
"secrets": "/var/lib/semaphore/secrets"
}
}

Regras para o caminho informado na aba File:

  • deve ser absoluto (/var/lib/semaphore/secrets/prod.json, e não prod.json);
  • não deve conter segmentos ..;
  • deve resolver para um local dentro do diretório de segredos (subdiretórios são permitidos);
  • o arquivo deve ser legível pelo usuário com o qual o Semaphore é executado (na imagem Docker oficial, esse usuário é semaphore, UID 1001).

Variáveis de ambiente não têm essa restrição; o servidor simplesmente lê a variável indicada do seu próprio ambiente.

2. Formatar o valor

O conteúdo do arquivo (ou o valor da variável) depende do tipo de chave. Uma única quebra de linha no final de um arquivo é ignorada; todo o restante é usado literalmente.

Chave SSH

O Semaphore espera um documento JSON, e não um arquivo de chave privada PEM ou OpenSSH bruto:

{
"login": "deploy",
"passphrase": "",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n"
}
  • login — o nome de usuário SSH, passado ao Ansible como --user. Deixe vazio para que o inventário decida (ansible_user). Para Repositórios Git, um login vazio assume git como padrão.
  • passphrase — a senha (passphrase) da chave privada, ou uma string vazia.
  • private_key — a chave privada com as quebras de linha codificadas como \n.

Gere o documento a partir de uma chave existente com o jq, que cuida do escape:

jq -n --arg login deploy --rawfile key ~/.ssh/id_ed25519 \
'{login: $login, passphrase: "", private_key: $key}' \
> /srv/semaphore/secrets/prod_ssh.json
chmod 0400 /srv/semaphore/secrets/prod_ssh.json

Em seguida, crie uma chave do tipo SSH, abra a aba File e informe /var/lib/semaphore/secrets/prod_ssh.json (o caminho como visto dentro do contêiner).

atenção

Apontar a aba File para uma chave privada bruta, como ~/.ssh/id_ed25519, não funciona. O arquivo é interpretado como JSON e a tarefa falha ao carregar o inventário.

Login com Senha

Também um documento JSON:

{
"login": "svc-ansible",
"password": "s3cr3t"
}

Deixe login vazio para usar a chave como um token ou senha simples, por exemplo como senha de um Ansible vault.

Exemplo com variável de ambiente

O mesmo formato JSON se aplica à aba Env. No Docker Compose:

services:
semaphore:
image: semaphoreui/semaphore:latest
environment:
PROD_SSH_KEY: '{"login":"deploy","passphrase":"","private_key":"-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n"}'

Crie uma chave SSH, selecione a aba Env e informe PROD_SSH_KEY como o nome da variável.

dica

Variáveis de ambiente são visíveis para todos os processos do contêiner e frequentemente acabam nos metadados e logs do orquestrador. Sempre que possível, prefira a aba File com um secret montado.

Solução de problemas

ErroCausaSolução
file path must be absoluteFoi informado um caminho relativoInforme o caminho completo começando com /
file path must not contain traversal segmentsO caminho contém ..Informe o caminho resolvido
file path must be inside secrets pathO arquivo está fora de dirs.secretsDefina SEMAPHORE_SECRETS_PATH como o diretório do arquivo, ou mova o arquivo
no such file or directoryO caminho está errado ou não foi montado no contêinerVerifique a montagem do volume e use o caminho de dentro do contêiner
permission deniedO processo do Semaphore não consegue ler o arquivoCorrija o proprietário ou as permissões do arquivo
invalid character '-' looking for beginning of valueFoi fornecida uma chave privada bruta em vez do documento JSONEnvolva a chave no JSON conforme mostrado acima