An Ansible role to install the following HashiCorp products from HashiCorp's official package repositories:
- Boundary
- Consul
- Nomad
- Packer
- Terraform
- Vagrant
- Vault
No configuration on the products is done. This is just an install through
the distribution's package manager (apt or dnf), with an optional pinned
version per product.
Nothing is installed by default. You must explicitly list the products
you want via hashicorp_products.
- Ansible >= 2.14
- A supported target OS (see below)
Every push and pull request triggers the single ci.yml workflow:
- The lint job runs
yamllintandansible-lint(production profile) against the role. - The functional jobs run the example playbook shown above
(
tests/test.yml) inside real Ubuntu 26.04, Debian 13, Fedora, Rocky Linux 10 and AlmaLinux 10 containers, plus armed arm64 containers (via QEMU) on Ubuntu 26.04 and Rocky Linux 10 to prove multi-architecture support, then verify thatterraform,vaultandconsulwere genuinely installed (including the pinned versions) by executing theirversioncommands. - The signing-key-behaviour job exercises the GPG key configuration:
installation with a single-string
hashicorp_gpg_key_fingerprints, the fail-closed path for an untrusted fingerprint, and automatic keyring self-healing.
Pushing a version tag (e.g. v1.2.3) publishes a release:
- All lint and functional jobs must pass for the tag.
- A GitHub release is created with generated release notes.
- The role is imported into Ansible Galaxy by running
ansible-galaxy role importagainstchrisvanmeer/ansible-role-hashicorp, using theGALAXY_API_KEYrepository secret (available at https://galaxy.ansible.com/ui/token).
The Galaxy publish only happens for a strict vX.Y.Z tag push — regular
pushes and pull requests never trigger it. The role is published here:
https://galaxy.ansible.com/ui/standalone/roles/chrisvanmeer/hashicorp/.
| OS family | Distributions |
|---|---|
| Debian | Debian, Ubuntu |
| RedHat (EL) | RHEL, CentOS, Rocky Linux, AlmaLinux (8+) |
| Fedora | Fedora |
Other operating systems will cause the role to fail with a clear error message instead of silently doing nothing.
The host architecture is detected automatically:
- On Debian/Ubuntu,
ansible_facts.architectureis mapped to the corresponding Debian architecture (x86_64->amd64,aarch64->arm64,armv7l/armv6l->armhf,ppc64le->ppc64el,s390x->s390x,riscv64->riscv64) and used for the APT repository entry, so packages are pulled for the host's native architecture. - On Fedora/EL, the repository's
$basearchhandles this natively. Unsupported architectures fail with a clear error at configuration time, not later duringapt update/dnf install.
Internally, the role picks its OS-specific variables (which in turn select
the task file to run) using an Ansible first_found lookup, checked in this
order:
vars/<distribution>-<major_version>.yml(e.g.vars/RedHat-9.yml)vars/<distribution>.yml(e.g.vars/Fedora.yml)vars/<os_family>.yml(e.g.vars/Debian.yml,vars/RedHat.yml)
This makes it straightforward to add a distribution- or version-specific override later (for example a different repository URL for a single EL major version) without touching the generic task logic.
Available variables are listed below, along with default values (see
defaults/main.yml):
hashicorp_products: []hashicorp_products is a list of dicts. Each item requires a name and
accepts an optional version:
hashicorp_products:
- name: terraform
version: "1.7.5" # pin an exact upstream version
- name: vault
version: "1.15.6"
- name: consul # no version -> latest available is installedValid values for name are: boundary, consul, nomad, packer,
terraform, vagrant, vault. Any other value, or a missing
name key, makes the role fail fast with an assertion error rather than
continuing with a typo.
Version pinning is passed through to the underlying package manager
(name=version* on APT, name-version* on DNF), so use the upstream
product version (e.g. 1.7.5), not the full Debian/RPM package revision.
If the requested version is not available in HashiCorp's repository for
your distribution, the task fails with the package manager's own error.
Other variables you generally won't need to touch:
hashicorp_apt_keyring_dir: /usr/share/keyrings
hashicorp_apt_keyring_path: "{{ hashicorp_apt_keyring_dir }}/hashicorp-archive-keyring.gpg"
hashicorp_gpg_key_url: https://apt.releases.hashicorp.com/gpg
hashicorp_rpm_gpg_key_url: https://rpm.releases.hashicorp.com/gpg
hashicorp_gpg_key_fingerprint: D55C0D1AC78A8D8126CB631CFC9CA96ACA026560
hashicorp_gpg_key_fingerprints:
- "{{ hashicorp_gpg_key_fingerprint }}"
- 798AEC654E5C15428C8E42EEAA16FCBCA621E701
hashicorp_rpm_revoked_keys:
- a621e701hashicorp_gpg_key_fingerprint is the current signing key. The actual
verification is done against hashicorp_gpg_key_fingerprints, which may
either be a single fingerprint string or a list of fingerprints (current
plus any previous keys you still want to accept during or after a
rotation). hashicorp_rpm_revoked_keys lists revoked key short-IDs that
are removed from the RPM database on Fedora/EL hosts.
HashiCorp rotates the GPG key signing its Linux packages from time to time (most recently on September 10th 2026, see HCSEC-2026-33). This role does the following to stay robust against such rotations:
- it always downloads the current key (
force: true) instead of trusting a cached copy; - it verifies the downloaded key's fingerprint against
hashicorp_gpg_key_fingerprintsbefore trusting it, and fails loudly if it is not listed — a tampered or hijacked key is never installed silently. Adding the new fingerprint during a rotation keeps both the old and the new key accepted while you roll out the change; - on APT hosts it refreshes the de-armored keyring whenever the verified key
is not yet present, so hosts that still have the pre-rotation key
(
AA16FCBCA621E701) recover automatically from theNO_PUBKEY FC9CA96ACA026560apt-update failure; - on RPM hosts it verifies the signing key up front and removes every
revoked key listed in
hashicorp_rpm_revoked_keys(default:gpg-pubkey-a621e701) from the RPM database so the rotated key is imported cleanly.
If HashiCorp rotates the key again, add the new fingerprint published on
hashicorp.com/trust/security to
hashicorp_gpg_key_fingerprints (optionally leaving the old one in place
for a transitional period) and existing hosts self-heal on their next run.
No dependencies.
Install this role with the following command:
ansible-galaxy install chrisvanmeer.hashicorp- hosts: servers
become: true
vars:
hashicorp_products:
- name: terraform
version: "1.15.8"
- name: vault
version: "2.0.4"
- name: consul
version: "2.0.3"
roles:
- role: chrisvanmeer.hashicorpNote: Vault and Consul moved to a 2.x versioning scheme in 2026; Terraform is
still on the 1.x line. Check each product's release notes for the current
version before pinning it in production.
MIT