Table of Contents
*O autor selecionou o Free and Open Source Fund para receber uma doação como parte do programa Write for DOnations.*
Introdução
O Vault, da Hashicorp, é uma ferramenta de código aberto usada para armazenar segredos e dados confidenciais de maneira segura em ambientes dinâmicos em nuvem. Ele fornece uma criptografia de dados forte, acesso baseado em identidade usando políticas personalizadas, leasing secreto e revogação, bem como um registro de auditoria detalhado que é registrado incessantemente. O Vault também possui uma API HTTP, tornando-o a escolha ideal para armazenar credenciais em implantações dispersas orientadas para o serviço, como o Kubernetes.
O Packer e o Terraform, também desenvolvidos pelo Hashicorp, podem ser usados juntos para criar e implantar imagens do Vault. Dentro desse fluxo de trabalho, os desenvolvedores podem usar o Packer para escrever imagens imutáveis para diferentes plataformas por meio de um único arquivo de configuração, que especifica o que a imagem deve conter. Então, o Terraform implanta quantas instâncias personalizadas das imagens criadas forem necessárias.
Neste tutorial, você usará o Packer para criar um snapshot imutável do sistema com o Vault instalado e orquestrar sua implantação usando o Terraform. No final, terá um sistema automatizado para implantar o Vault em funcionamento, permitindo que você se concentre em trabalhar com o Vault em si e não com o processo de instalação e fornecimento subjacentes.
Pré-requisitos
- O Packer instalado em sua máquina local. Para instruções, visite a documentação oficial.
- O Terraform instalado em sua máquina local. Visite a documentação oficial para um guia.
- Um token de acesso pessoal (chave API) com permissões de leitura e escrita para sua conta the cloud provider. Para aprender como criar uma chave API, visite Como criar um token de acesso pessoal nos docs.
- Uma chave SSH que você usará para autenticar-se com os Droplets implantados pelo Vault, disponível em sua máquina local e adicionada em sua conta the cloud provider. Você também precisará de suas digitais, que você pode copiar da página Security de sua conta assim que as tiver adicionado. Veja a documentação da the cloud provider para instruções detalhadas ou o tutorial sobre Como configurar chaves SSH.
Passo 1 — Como criar um template do Packer
Nesta etapa, você escreverá um arquivo de configuração do Packer, chamado de _template_ (modelo), que instruirá o Packer sobre como construir uma imagem que contém o Vault pré-instalado. Você escreverá a configuração no formato JSON, um formato de configuração legível comumente usado.
Para os fins deste tutorial, você armazenará todos os arquivos em ~/vault-orchestration. Crie o diretório executando o seguinte comando:
mkdir ~/vault-orchestration
Navegue até ele:
cd ~/vault-orchestration
Os arquivos de configuração para o Packer e Terraform serão armazenados separadamente, em diferentes sub-diretórios. Crie-os usando o seguinte comando:
mkdir packer terraform
Como trabalhará primeiro com o Packer, navegue até o respectivo diretório:
cd packer
Como usar variáveis do modelo
O controle de dados privados e de segredos de aplicativo em um arquivo separado de variáveis é a maneira ideal de mantê-los fora do seu modelo. Ao construir a imagem, o Packer substituirá as variáveis referenciadas pelos seus valores. Ter valores secretos codificados no seu modelo é um risco de segurança, especialmente se ele for compartilhado com membros da equipe ou colocado em sites públicos, como o GitHub.
Você os armazenará no subdiretório packer, em um arquivo chamado variables.json. Crie-o usando seu editor de texto favorito:
nano variables.json
Adicione as linhas a seguir:
[label ~/vault-orchestration/packer/variables.json]
{
"do_token": "<^>your_do_api_key<^>",
"base_system_image": "ubuntu-18-04-x64",
"region": "nyc3",
"size": "s-1vcpu-1gb"
}
O arquivo de variáveis consiste em um dicionário JSON, que mapeia nomes de variáveis aos seus valores. Você usará essas variáveis no modelo que está prestes a criar. Se quiser, é possível editar o tamanho de imagem base, região e do Droplet, de acordo com a documentação do desenvolvedor.
Lembre-se de substituir o <^>your_do_api_key<^> pela sua chave API que criou como parte dos pré-requisitos e, em seguida, salve e feche o arquivo.
Como criar compiladores e provisionadores
Com o arquivo de variáveis pronto, você agora criará o modelo do Packer em si.
Você armazenará o modelo do Packer para o Vault em um arquivo chamado template.json. Crie-o usando seu editor de texto:
nano template.json
Adicione as linhas a seguir:
[label ~/vault-orchestration/packer/template.json]
{
"builders": [{
"type": "the cloud provider",
"api_token": "{{user `do_token`}}",
"image": "{{user `base_system_image`}}",
"region": "{{user `region`}}",
"size": "{{user `size`}}",
"ssh_username": "root"
}],
"provisioners": [{
"type": "shell",
"inline": [
"sleep 30",
"sudo apt-get update",
"sudo apt-get install unzip -y",
"curl -L <^>https://releases.hashicorp.com/vault/1.3.2/vault_1.3.2_linux_amd64.zip<^> -o vault.zip",
"unzip vault.zip",
"sudo chown root:root vault",
"mv vault /usr/local/bin/",
"rm -f vault.zip"
]
}]
}
No modelo, você define matrizes de _construtores_ e de _provisionadores_. Os construtores dizem ao Packer como compilar a imagem do sistema (segundo seu tipo) onde armazená-la, enquanto os provisionadores contém conjuntos de ações que o Packer deve realizar no sistema antes de transformá-la em uma imagem imutável, como a instalação ou configuração de software. Sem qualquer provisionador, você acabaria com uma imagem do sistema base intocada. Tanto os construtores como os provisionadores exportam parâmetros para maior personalização de fluxos de trabalho.
Primeiro, você define um único construtor do tipo the cloud provider, o que significa que quando ele for ordenado a compilar uma imagem, o Packer usará os parâmetros fornecidos para criar um Droplet temporário do tamanho definido usando a chave de API fornecida, com a imagem do sistema base e região especificadas. O formato para buscar uma variável é o {{user '<^>variable_name<^>'}}, onde a parte destacada é seu nome.
Quando o Droplet temporário é provisionado, o provisionador se conectará a ele usando o SSH com o nome de usuário especificado e executará sequencialmente todos os provisionadores definidos antes da criação de um Snapshot da the cloud provider por meio do Droplet e da exclusão desse Snapshot.
Ele é do tipo shell, que executará os comandos dados no destino. Os comandos podem ser especificados tanto como inline (em linha), como matrizes e strings, ou definidos em arquivos de script separados caso inseri-los no modelo torne-se algo complicado devido ao tamanho. Os comandos no modelo esperam 30 segundos para o sistema inicializar e então baixam e descompactam o Vault <^>1.3.2<^>. Verifique a página oficial de download do Vault e substitua o link nos comandos por uma versão mais recente para o Linux, se estiver disponível.
Quando terminar, salve e feche o arquivo.
Para verificar a validade do seu modelo, execute o seguinte comando:
packer validate -var-file=variables.json template.json
O Packer aceita um caminho para o arquivo de variáveis por meio do argumento -var-file.
Você verá o seguinte resultado:
[secondary_label Output]
Template validated successfully.
Se receber um erro, o Packer especificará exatamente onde ele ocorreu. Assim, será possível corrigi-lo.
Agora, você tem um modelo de trabalho que produz uma imagem com o Vault instalado, com sua chave de API e outros parâmetros definidos em um arquivo separado. Agora, tudo está pronto para invocar o Packer e compilar o snapshot.
Passo 2 — Como compilar o Snapshot
Nesta etapa, você compilará um Snapshot da the cloud provider do seu modelo usando o comando build do Packer.
Para compilar seu snapshot, execute o seguinte comando:
packer build -var-file=variables.json template.json
Esse comando levará algum tempo para ser finalizado. Você verá um resultado extenso, que se parecerá com este:
[secondary_label Output]
the cloud provider: output will be in this color.
==> the cloud provider: Creating temporary ssh key for droplet...
==> the cloud provider: Creating droplet...
==> the cloud provider: Waiting for droplet to become active...
==> the cloud provider: Using ssh communicator to connect: ...
==> the cloud provider: Waiting for SSH to become available...
==> the cloud provider: Connected to SSH!
==> the cloud provider: Provisioning with shell script: /tmp/packer-shell035430322
...
==> the cloud provider: % Total % Received % Xferd Average Speed Time Time Time Current
==> the cloud provider: Dload Upload Total Spent Left Speed
the cloud provider: Archive: vault.zip
==> the cloud provider: 100 45.5M 100 45.5M 0 0 154M 0 --:--:-- --:--:-- --:--:-- 153M
the cloud provider: inflating: vault
==> the cloud provider: Gracefully shutting down droplet...
==> the cloud provider: Creating snapshot: packer-1581537927
==> the cloud provider: Waiting for snapshot to complete...
==> the cloud provider: Destroying droplet...
==> the cloud provider: Deleting temporary ssh key...
Build 'the cloud provider' finished.
==> Builds finished. The artifacts of successful builds are:
--> the cloud provider: A snapshot was created: 'packer-1581537927' <^>(ID: 58230938)<^> in regions '...'
O Packer registra todas as etapas tomadas na construção do modelo. A última linha contém o nome do snapshot (como packer-1581537927) e seu ID entre parênteses, marcado em vermelho. Anote o ID do snapshot, pois você precisará dele no próximo passo.
Se o processo de compilação falhar devido a erros da API, espere alguns minutos e, em seguida, tente novamente.
Você criou um Snapshot da the cloud provider, de acordo com seu modelo. O snapshot tem o Vault pré-instalado e agora é possível implantar Droplets com ele como a imagem do sistema deles. Na próxima etapa, será escrita a configuração do Terraform para automatizar tais implantações.
Passo 3 — Escrevendo a configuração do Terraform
Nesta etapa, será escrita a configuração do Terraform para automatizar implantações de Droplets do snapshot que contém o Vault que você acabou de compilar usando o Packer.
Antes de escrever de fato a configuração do Terraform para implantar o Vault do snapshot previamente compilado, será necessário primeiro configurar o provedor da the cloud provider para ele. Navegue até o subdiretório terraform, executando:
cd ~/vault-orchestration/terraform
Então, crie um arquivo chamado do-provider.tf, onde você armazenará o provedor:
nano do-provider.tf
Adicione as linhas a seguir:
[label ~/vault-orchestration/terraform/do-provider.tf]
variable "do_token" {
}
variable "ssh_fingerprint" {
}
variable "instance_count" {
default = "1"
}
variable "do_snapshot_id" {
}
variable "do_name" {
default = "vault"
}
variable "do_region" {
}
variable "do_size" {
}
variable "do_private_networking" {
default = true
}
provider "the cloud provider" {
token = var.do_token
}
Esse arquivo declara variáveis de parâmetro e fornece uma chave de API ao provedor the cloud provider. Mais tarde, você usará essas variáveis em seu modelo do Terraform, mas será necessário primeiro especificar os valores delas. Por esse motivo, o Terraform é compatível com a especificação de valores de variáveis em um _arquivo de definições de variáveis_, de maneira semelhante ao Packer. O nome do arquivo deve terminar em .tfvars ou .tfvars.json. Mais tarde, você passará esse arquivo para o Terraform usando o argumento -var-file.
Salve e feche o arquivo.
Crie um arquivo de definições de variáveis chamado definitions.tfvars usando seu editor de texto:
nano definitions.tfvars
Adicione as linhas a seguir:
[label ~/vault-orchestration/terraform/definitions.tf]
do_token = "<^>your_do_api_key<^>"
ssh_fingerprint = "<^>your_ssh_key_fingerprint<^>"
do_snapshot_id = <^>your_do_snapshot_id<^>
do_name = "vault"
do_region = "nyc3"
do_size = "s-1vcpu-1gb"
instance_count = 1
Lembre-se de substituir o <^>your_do_api_key<^>, <^>your_ssh_key_fingerprint<^> e <^>your_do_snapshot_id<^> pela chave de API da sua conta, a digital da sua chave SSH e pelo ID do snapshot que você anotou na etapa anterior, respectivamente. Os parâmetros do do_region e do_size devem ter os mesmos valores que no arquivo de variáveis do Packer. Se quiser implantar várias instâncias de uma vez, ajuste o instance_count para o valor desejado.
Quando terminar, salve e feche o arquivo.
Para obter mais informações sobre o provedor Terraform da the cloud provider, visite os docs oficiais.
Você armazenará a configuração de implantação do snapshot do Vault em um arquivo chamado deployment.tf, dentro do diretório terraform. Crie-o usando seu editor de texto:
nano deployment.tf
Adicione as linhas a seguir:
[label ~/vault-orchestration/terraform/deployment.tf]
resource "the cloud provider_droplet" "vault" {
count = var.instance_count
image = var.do_snapshot_id
name = var.do_name
region = var.do_region
size = var.do_size
private_networking = var.do_private_networking
ssh_keys = [
var.ssh_fingerprint
]
}
output "instance_ip_addr" {
value = {
for instance in the cloud provider_droplet.vault:
instance.id => instance.ipv4_address
}
description = "The IP addresses of the deployed instances, paired with their IDs."
}
Aqui, você define um único _recurso_ do tipo the cloud provider_droplet chamado vault. Então, defina os parâmetros de acordo com os valores das variáveis e adicione uma chave SSH (usando sua digital) de sua conta the cloud provider para o recurso do Droplet. Por fim, você transmite os endereços IP de todas as instâncias recém-implantadas para o console.
Salve e feche o arquivo.
Antes de fazer qualquer coisa com sua configuração de implantação, será necessário inicializar o diretório como um projeto Terraform:
terraform init
Você verá o seguinte resultado:
[secondary_label Output]
Initializing the backend...
Initializing provider plugins...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.the cloud provider: version = "~> 1.14"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Ao inicializar um diretório como um projeto, o Terraform lê os arquivos de configuração disponíveis e baixa plug-ins considerados necessários, conforme registrado no resultado.
Agora, está pronta a configuração do Terraform para implantar seu snapshot do Vault. Agora, é possível seguir em frente para validá-lo e implantá-lo em um Droplet.
Passo 4 — Como implantar o Vault usando o Terraform
Nesta seção, você verificará sua configuração do Terraform usando o comando validate. Assim que for verificada com sucesso, você a aplicará e implantará um Droplet como resultado.
Execute o seguinte comando para testar a validade da sua configuração:
terraform validate
Você verá o seguinte resultado:
[secondary_label Output]
Success! The configuration is valid.
Em seguida, execute o comando plan para ver o que o Terraform tentará fazer ao provisionar a infraestrutura de acordo com sua configuração:
terraform plan -var-file="definitions.tfvars"
O Terraform aceita um arquivo de definições de variáveis por meio do parâmetro -var-file.
O resultado será semelhante a:
[secondary_label Output]
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# the cloud provider_droplet.vault[0] will be created
+ resource "the cloud provider_droplet" "vault" {
...
}
Plan: 1 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
O + verde no início da linha resource "the cloud provider_droplet" "vault" significa que o Terraform criará um novo Droplet chamado vault, usando os parâmetros que seguem. Isso está correto. Portanto, execute agora o plano pelo comando terraform apply:
terraform apply -var-file="definitions.tfvars"
Digite yes quando solicitado. Após alguns minutos, o Droplet terminará o provisionamento e você verá um resultado semelhante a este:
[secondary_label Output]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ the cloud provider_droplet.vault-droplet
...
Plan: 1 to add, 0 to change, 0 to destroy.
...
the cloud provider_droplet.vault-droplet: Creating...
...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
instance_ip_addr = {
"181254240" = "<^>your_new_server_ip<^>"
}
No resultado, o Terraform registra as ações que ele realizou (neste caso, para criar um Droplet) e mostra o endereço IP público dele no final. Você o usará para se conectar ao seu novo Droplet na próxima etapa.
Você criou um novo Droplet do snapshot que contém o Vault e agora tudo está pronto para verificá-lo.
Passo 5 — Como verificar seu Droplet implantado
Nesta etapa, você acessará seu novo Droplet usando o SSH e verificará se o Vault foi instalado corretamente.
Em máquinas Linux e macOS, utilize o comando ssh já disponível para se conectar:
ssh root@<^>your_server_ip<^>
Digite yes quando solicitado. Assim que estiver logado, rode o Vault executando:
vault
Você verá o resultado "ajuda", que se parece com este:
[secondary_label Output]
Usage: vault <command> [args]
Common commands:
read Read data and retrieves secrets
write Write data, configuration, and secrets
delete Delete secrets and configuration
list List data or secrets
login Authenticate locally
agent Start a Vault agent
server Start a Vault server
status Print seal and HA status
unwrap Unwrap a wrapped secret
Other commands:
audit Interact with audit devices
auth Interact with auth methods
debug Runs the debug command
kv Interact with Vault's Key-Value storage
lease Interact with leases
namespace Interact with namespaces
operator Perform operator-specific tasks
path-help Retrieve API help for paths
plugin Interact with Vault plugins and catalog
policy Interact with policies
print Prints runtime configurations
secrets Interact with secrets engines
ssh Initiate an SSH session
token Interact with tokens
Finalize a conexão digitando exit.
Agora, você verificou que seu Droplet recém-implantado foi criado do snapshot que você fez e que o Vault está instalado corretamente.
Conclusão
Agora, você tem um sistema automatizado para implantar o Vault da Hashicorp em Droplets da the cloud provider usando o Terraform e o Packer. Agora, é possível implantar quantos servidores Vault você quiser. Para começar a usar o Vault, será necessário inicializá-lo e configurá-lo ainda mais. Para instruções sobre como fazer isso, visite os docs oficiais.
Para outros tutoriais usando o Terraform, confira nossa página de conteúdo do Terraform.