A role to deploy a production grade HashiCorp Vault.
The following scenarios are currently run with Molecule via GitHub Actions on all pull requests to the master
branch.
default
tests a single Vault install on CentOS 8 with file storageintegrated
tests a single Vault install on Ubuntu 20.04 with Integrated storage
Ansible variables are listed below, along with default values (see defaults/main.yml
):
- If true, Ansible will not copy over certificates, template out configuration files, or start the Vault service. Useful if building a base image with Vault installed
- Default value:
false
- If true, Ansible will install Vault via the official HashiCorp repository. If false, Vault can be installed via remote or local download
- Default value:
false
- If true, Ansible will install the enterprise version of Vault. This is only supported when installing from the HashiCorp repository
- Default value:
false
- The name of the inventory group
- Default value:
vault
- OS user name
- Default value:
vault
- OS group name
- Default value:
vault
- If true, Ansible will create the user and group defined in
vault_user
andvault_group
- Default value:
true
- Location of Vault's home directory
- Default value:
/etc/vault.d
- Location of Vault's data directory
- Default value:
/opt/vault
- Location of the Vault binary
- Default value:
/usr/bin
- Location of the TLS certificates
- Default value:
/opt/vault/tls
- Location of the Vault license
- Default value:
/opt/vault/license
- Location of the Vault configuration file
- Default value:
/etc/vault.d/vault.hcl
- If true, Ansible will create a plugins directory
- Default value:
false
- Location of the plugin directory
- Default value:
/etc/vault.d/plugins
- Version of Vault to install
- Default value:
1.11.3
- Name of the Vault file archive to download
- Default value:
vault_1.11.3_linux_amd64.zip
- Full remote URL location to the vault archive
- Default value:
https://releases.hashicorp.com/vault/1.11.3/vault_1.11.3_linux_amd64.zip
- If set, Ansible will locally look for the Vault binary at the specified path
- No default value
- If set, Ansible will create a license file using this value for the file content
- No default value. A license is required for Vault versions >= 1.8.0 when installing enterprise, so you have to provide either
vault_license_string
orvault_license_file
- If set, Ansible will locally look for a Vault license at the specified path
- No default value. A license is required for Vault versions >= 1.8.0 when installing enterprise, so you have to provide either
vault_license_string
orvault_license_file
- The address to which Vault will bind client interfaces
- Default value:
0.0.0.0
- Vault API port
- Default value:
8200
- The name of the Vault cluster
- Default value: none
- Vault cluster port
- Default value:
8201
- If true, Ansible will enable the Vault UI
- Default value:
true
- The cloud provider Vault will be deployed to. This is used for Raft's auto-join feature. Refer to this document to determine what keys are needed for each cloud environment. On-prem/VMWare installs would set this to
none
- Type:
dictionary
- Default value:
provider: 'none'
- Storage backend to use (supports file, integrated, gcs, or Consul)
- Default value:
integrated
- Name of the Google Cloud Storage bucket (only used when
vault_storage_backend
isgcs
) - No default value
- Specifies if high availability mode is enabled (only used when
vault_storage_backend
isgcs
) - No default value
- Specifies telemetry configuration to Vault. Refer to this document for available parameters. Each parameter can be passed as a key to this dictionary
- No default value
- Specifies service registrtation configuration for Vault. Refer to this document for available parameters. Each parameter can be passed as a key to this dictionary
- No default value
- A dictionary defining the seal type to use for Vault. Refer to this document for the required parameters to pass as keys if using a cloud KMS solution.
- Type:
dictionary
- Default value:
type: 'shamir'
- If true, Vault will not request for a client certificate when accessed
- Default value: true
- If set, Ansible will locally look for a TLS CA certificate at the specified path to copy to each Vault server. Mutually exclusive with
vault_tls_ca_cert_string
- No default value
- If set, Ansible will Ansible will create the TLS CA file using this value for the file content. Mutually exclusive with
vault_tls_ca_cert_file
- No default value
- If set, Ansible will locally look for a TLS certificate at the specified path to copy to each Vault server. Mutually exclusive with
vault_tls_cert_string
- No default value
- If set, Ansible will Ansible will create the TLS certificate using this value for the file content. Mutually exclusive with
vault_tls_cert_file
- No default value
- If set, Ansible will locally look for a TLS key at the specified path to copy to each Vault server. Mutually exclusive with
vault_tls_key_string
- No default value
- If set, Ansible will Ansible will create the TLS key using this value for the file content. Mutually exclusive with
vault_tls_cert_file
- No default value
- If Set, Vault will use this TLS server name when connecting with HTTPS. Uses the server's hostname if not set.
- No default value
- Port to use to connect to the local Consul agent
- Default value:
8500
- Scheme to use to connect to the local Consul agent
- Default value:
http
- Consul ACL token that Vault should use
- No default value
- Location of the TLS certificates for Consul
- Default value:
/opt/vault/consul
- If set, Ansible will locally look for a TLS CA certificate at the specified path to copy to each Vault server for connecting to Consul
- No default value
- If set, Ansible will locally look for a signed TLS certificate at the specified path to copy to each Vault server for connecting to Consul
- No default value
- If set, Ansible will locally look for a TLS key at the specified path to copy to each Vault server for connecting to Consul
- No default value
- If true, Vault will skip verification of the certificate presented by Consul
- Default value:
false
- Path to Vault's data in Consul's key value storage
- Default value:
vault/
- Consul cluster if using Consul as backend storage.
The following example deploys a three node Vault cluster with Integrated storage.
Using Google Cloud Platform for this example.
$ export GOOGLE_CLOUD_PROJECT=<your_gcp_project_id>
# creation a bastion node to run playbook from
$ gcloud compute instances create bastion \
--async \
--zone us-central1-a \
--boot-disk-size 50GB \
--image-family ubuntu-2004-lts \
--image-project ubuntu-os-cloud \
--machine-type n1-standard-1 \
--tags vault
# create three nodes in GCP
$ for i in 1 2 3; do
gcloud compute instances create vault0${i} \
--async \
--zone us-central1-a \
--boot-disk-size 50GB \
--image-family ubuntu-2004-lts \
--image-project ubuntu-os-cloud \
--machine-type n1-standard-1 \
--tags vault
done
# SSH to bastion node
$ gcloud compute ssh bastion --zone us-central1-a
# optional: generate SSL certificates
$ consul tls ca create
==> Saved consul-agent-ca.pem
==> Saved consul-agent-ca-key.pem
$ consul tls cert create -server \
-additional-dnsname=vault01.c.$GOOGLE_CLOUD_PROJECT.internal \
-additional-dnsname=vault02.c.$GOOGLE_CLOUD_PROJECT.internal \
-additional-dnsname=vault03.c.$GOOGLE_CLOUD_PROJECT.internal
...
==> Using consul-agent-ca.pem and consul-agent-ca-key.pem
==> Saved dc1-server-consul-0.pem
==> Saved dc1-server-consul-0-key.pem
# create the inventory file
$ cat <<EOF > inventory
[vault_primary]
vault01.c.$GOOGLE_CLOUD_PROJECT.internal
vault02.c.$GOOGLE_CLOUD_PROJECT.internal
vault03.c.$GOOGLE_CLOUD_PROJECT.internal
EOF
# create the playbook
$ cat <<EOF > site.yml
---
- hosts: vault_primary
become: yes
roles:
- role: ansible-role-vault
EOF
# optional: create group_vars directory and file
$ mkdir group_vars
$ cat <<EOF > vault_primary.yml
---
vault_storage_backend: 'integrated'
vault_version: '1.11.3+ent'
vault_tls_ca_cert_file: 'tls/consul-agent-ca.pem'
vault_tls_cert_file: 'tls/dc1-server-consul-0.pem'
vault_tls_key_file: 'tls/dc1-server-consul-0-key.pem'
vault_tls_disable_client_certs: false
vault_ansible_group: vault_primary
vault_seal:
type: gcpkms
project: $GOOGLE_CLOUD_PROJECT
region: us-central1
key_ring: vault_key_ring
crypto_key: vault_crypto_key
EOF
# run ansible playbook
$ ansible-playbook -i inventory site.yaml
# export address for binary
$ export VAULT_ADDR=https://vault01.c.[PROJECT_ID].internal:8200
# optional: disable SSL verification
$ export VAULT_SKIP_VERIFY=true
# initalize the Vault cluster (if using Shamir)
$ vault operator init -key-shares=1 -key-threshold=1
Unseal Key 1: tMoFtiYOuBlf6757jjOl4lCvN1v4NneZhzQqwe3pzxA=
Initial Root Token: s.8OZR9fj3g3mJoxDKlUaE48Yx
Success! Vault is initialized
...
# initalize the Vault cluster (if using Autounseal)
$ vault operator init -recovery-shares=1 -recovery-threshold=1
Recovery Key 1: tMoFtiYOuBlf6757jjOl4lCvN1v4NneZhzQqwe3pzxA=
Initial Root Token: s.8OZR9fj3g3mJoxDKlUaE48Yx
Success! Vault is initialized
...
# unseal each Vault node if using Shamir
$ vault operator unseal tMoFtiYOuBlf6757jjOl4lCvN1v4NneZhzQqwe3pzxA
# authenticate to Vault with the root token
$ vault login s.8OZR9fj3g3mJoxDKlUaE48Yx
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
...
# verify raft peer list
$ vault operator raft list-peers
Node Address State Voter
---- ------- ----- -----
vault01.c.[PROJECT_ID].internal vault01.c.[PROJECT_ID].internal:8201 leader true
vault02.c.[PROJECT_ID].internal vault02.c.[PROJECT_ID].internal:8201 follower true
vault03.c.[PROJECT_ID].internal vault03.c.[PROJECT_ID].internal:8201 follower true
Jacob Mammoliti