DEBOPS.HASHICORP(5)

NAME
debops.hashicorp - Securely install HashiCorp applications

SYNOPSIS

debops run service/hashicorp [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

The debops.hashicorp Ansible role can be used to securely install HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications, such as Consul <https://consul.io/>, Terraform <https://terraform.io/>, Vault <https://vaultproject.io/> and others.

The selected applications are downloaded from the HashiCorp release repository, authenticated using the HashiCorp OpenPGP key and installed on the system. After that, other Ansible roles can be used to configure them as needed.

GETTING STARTED

  Initial configuration

The debops.hashicorp role does not install any HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications by default, even if enabled in the Ansible inventory. You need to specify the application names you wish to install using the hashicorp__applications list. For example, to install consul on all hosts that use the role, create a file in the Ansible inventory with contents:

hashicorp__applications: [ 'consul' ]

The role will install the consul binary, after verifying its authenticity, in the /usr/local/bin directory so that it will be automatically available for all users.

List of HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications supported by the role can be found in the hashicorp__default_version_map default variable. You can also use it to easily install all supported applications at once:

hashicorp__applications: '{{ hashicorp__default_version_map.keys() }}'

After the binaries are installed, they are ready to be configured by other Ansible roles. See the Ansible integration document for more details.

  Example inventory

The debops.hashicorp Ansible role is not enabled by default. To enable it on a host, you need to include that host in the [debops_service_hashicorp] inventory group:

[debops_service_hashicorp]
hostname

  Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.hashicorp role:

---
- name: Install HashiCorp applications
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_hashicorp' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  roles:
    - role: keyring
      tags: [ 'role::keyring', 'skip::keyring', 'role::hashicorp' ]
      keyring__dependent_gpg_keys:
        - '{{ hashicorp__keyring__dependent_gpg_keys }}'
    - role: hashicorp
      tags: [ 'role::hashicorp', 'skip::hashicorp' ]

DEBOPS.HASHICORP SECURITY CONSIDERATIONS

  Role security guidelines

Because the debops.hashicorp role can be used to install binary Go applications on production systems, it was designed to check and validate the archives used for application deployment against a known Trust Path. This document explains the steps taken by the role to authenticate and verify the installed software.

  HashiCorp applications in Debian Software Repository

The Debian Go Packaging Team <https://qa.debian.org/developer.php?login=pkg-go-maintainers%40lists.alioth.debian.org> maintains source and binary packages of selected HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications in the Debian Software Repository. The Debian packages for different applications should be the preferred installation method when they are readily available on the Debian Stable release.

The debops.hashicorp role is written in the belief that the verified and authenticated access to the upstream versions of HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications, even though installed using binary packages, can still be useful, for example to provide secure installation path to the software not packaged in Debian.

  Software sources

The HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> company publishes the source code of each application on GitHub, in the hashicorp organization <https://github.com/hashicorp/>. Each release is tagged using git tags. Each tag is signed by the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key.

The process that HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> uses to build binary Go packages from the sources on GitHub and deploy them on their release page is currently unpublished.

It is unknown if the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> application builds are reproducible and can be independently verified.

Each released version of an application is published on the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> release page <https://releases.hashicorp.com/>. The applications are published as versioned .zip archives, each archive containing one or more Go binaries. Each archive file is hashed using SHA256 algorithm. Hashes of all provided files are stored in a separate file which is signed by the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key.

  HashiCorp OpenPGP key

The HashiCorp Security Policy <https://www.hashicorp.com/security.html> page contains information about the OpenPGP key used to sign the application releases. The OpenPGP key fingerprint of the key used by HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> is:

C874 011F 0AB4 0511 0D02 1055 3436 5D94 72D7 468F

The HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key is published on the keybase.io <https://keybase.io> website, on the hashicorp account <https://keybase.io/hashicorp>. The key is tracked by several other users of the site.

The HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key is published in the Ubuntu keyserver <https://keyserver.ubuntu.com/> and can be imported from there using the gpg command:

user@host:~$ gpg --keyserver hkp://keyserver.ubuntu.com \
                 --recv-key C874011F0AB405110D02105534365D9472D7468F

  Software installation procedure

The steps outlined below describe the method used by the debops.hashicorp role to verify and install the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications selected by the user or another Ansible role:

•   The debops.hashicorp Ansible role creates a separate, unprivileged system group and UNIX user account, by default both named hashicorp. The account does not provide shell access and uses /usr/sbin/nologin shell by default.

    Additionally, several directories owned by the new user account are created to provide location to unpack the verified archives in preparation for the installation.

•   The hashicorp user account imports the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key from the OpenPGP keyserver.

•   The hashicorp user account downloads the necessary files from the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> release page over the HTTPS protocol. These files include: binary archive files, files containing SHA256 hashes of the provided files, files containing OpenPGP signatures of the hash files.

•   The hashicorp user account verifies the signature of the SHA256 hash file against the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> OpenPGP key imported prior.

•   If the signature verification passed, the hashicorp user compares the SHA 256 hashes provided in the signed file against the downloaded binary archives.

•   If the hash verification was successful, the hashicorp user account unpacks the binary archives of the HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications to separate directories created prior.

•   The root user account installs the unpacked application binaries to the specified directory (by default /usr/local/bin) with root:root owner and group. Additional files required by the Consul Web UI are copied to specified web root directory (by default /srv/www/consul/sites/public/) when the Consul Web UI is enabled.

    All of the downloaded and unpacked files are left intact to allow for idempotent operation and verification.

ANSIBLE INTEGRATION

  Support for other Ansible roles

The debops.hashicorp Ansible role is designed to be used by other Ansible roles as role dependency. By design, the application binaries are installed in the specified path and the rest of the service configuration, including service process manager configuration, firewall, TCP/UDP port registration in /etc/services, etc. is left to the user or other Ansible roles.

To facilitate seamless role integration, debops.hashicorp role provides a set of default variables and Ansible local facts that can be used by other Ansible roles idempotently. Thus, the modification of the role itself shouldn't be needed, and it can should be easily integrated in the different playbooks and environments.

  Default variables available to other roles

You can use these variables in the playbook to influence the operation of the debops.hashicorp role from another role:

hashicorp__dependent_packages
    List of APT packages which should be installed when the debops.hashicorp role is executed.

hashicorp__dependent_applications
    List of HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications which should be installed by the debops.hashicorp role. For the list of available applications, refer to the hashicorp__default_version_map variable.

hashicorp__consul_webui
    Boolean variable which enables installation of additional files needed to serve the Consul Web UI page. The role will remember the Web UI installation state to ensure idempotence.

  Examples

In a hypothetical consul Ansible role create a default variable:

consul__hashicorp_application: 'consul'

Next, in the playbook that executes your role, include the debops.hashicorp role with your custom variable:

- name: Deploy Consul
  hosts: all
  become: True
  roles:
    - role: hashicorp
      hashicorp__dependent_applications:
        - '{{ consul__hashicorp_application }}'
    - role: consul

This playbook will then install the Consul <https://consul.io/> application after verification, and configure it using your own Ansible role. Make sure that you use YAML list syntax correctly, otherwise the debops.hashicorp role will fail due to wrong variable type mismatch. To install multiple applications at once, you can use a different variant of the variables and playbook.

The variables, with addition of the Consul Web UI:

consul__hashicorp__dependent_applications: [ 'consul', 'consul-template' ]
consul__hashicorp__consul_webui: True

The playbook:

- name: Deploy Consul and Consul Template
  hosts: all
  become: True
  roles:
    - role: hashicorp
      hashicorp__dependent_applications: '{{ consul__hashicorp__dependent_applications }}'
      hashicorp__consul_webui: '{{ consul__hashicorp__consul_webui | bool }}'
    - role: consul

  Ansible local facts

The debops.hashicorp role maintains a set of Ansible local facts with information about the installed applications. Other roles can use these facts in an idempotent way to prepare their own configuration. These facts are:

ansible_local.hashicorp.installed
    Boolean. If True, the role has been correctly configured.

ansible_local.hashicorp.applications
    YAML dictionary which specifies all currently installed HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> applications as keys and their versions as values.

ansible_local.hashicorp.bin
    Path to the directory where binaries are installed, by default /usr/local/bin.

ansible_local.hashicorp.consul_webui
    Boolean. If True, the Consul Web UI files have been downloaded and installed.

ansible_local.hashicorp.consul_webui_path
    Path to the Consul Web UI files, by default /srv/www/consul/sites/public.

  Examples

Check if specific HashiCorp <https://en.wikipedia.org/wiki/HashiCorp> application is installed on a host:

consul_is_installed: '{{ True
                         if (ansible_local.hashicorp.applications | d() and
                             'consul' in ansible_local.hashicorp.applications.keys())
                         else False }}'

Register the installed application version to conditionally check when the version changed and restart the daemon:

consul_version: '{{ (ansible_local.hashicorp.applications["consul"] | d())
                     if (ansible_local.hashicorp.applications | d())
                     else "") }}'

AUTHOR
Maciej Delmanowski

COPYRIGHT
2014-2024, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others