DEBOPS.KEYRING(5)

NAME
debops.keyring - Manage APT keyring and UNIX account GPG keyring via Ansible

SYNOPSIS

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

debops run site --tags role::keyring [playbook] ... [--limit group,host,...] [--diff] [--check] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

debops run site --skip-tags skip::keyring [playbook] ... [--limit group,host,...] [--diff] [--check] [--tags-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

The debops.keyring Ansible role is designed as a helper for other Ansible roles that manages the APT keyring as well as the GPG keyrings on unprivileged UNIX accounts. Other Ansible roles can tell the debops.keyring role which GPG keys should be present or absent in the selected keyrings; the role then retrieves the GPG keys either from:

•   local key store in the debops.keyring role, or located in a directory on the Ansible Controller, or

•   specified URL, or

•   specified Keybase <https://keybase.io/> profile via the Keybase API <https://keybase.io/docs/api/1.0/call/user/pgp_keys.asc>, or

•   a default GPG keyserver, if defined

    WARNING: The role is not meant to be used via Ansible inventory to manage the APT or GPG keys; users can use the debops.apt role to manage the APT keyring via the inventory.

    At the moment there is no solution for unprivileged UNIX account keyrings manageable via the inventory. This functionality will be implemented later via other DebOps roles that manage UNIX accounts.

GETTING STARTED

  Default remote keyserver

By default the debops.keyring role uses the Ubuntu keyserver <https://keyserver.ubuntu.com/> to retrieve the GPG keys based on their fingerprints. The default keyserver is configured using the keyring__keyserver variable. For increased security, or if your infrastructure is located behind a firewall that blocks connections to the OpenPGP keyserver, you can use the debops.sks Ansible role to set up a local instance of a SKS keyserver and import the GPG keys to it for easy retrieval.

Previously used SKS Keyserver pool <https://sks-keyservers.net/> has been deprecated and won't be maintained anymore. Thanks to the maintainers for years of great service!

  Local key store on the Ansible Controller

The role supports usage of a local key store on the Ansible Controller, by setting the absolute path to a directory with the GPG key files in the keyring__local_path variable. For example, to store the GPG keys inside of the DebOps project directory, ansible/keyring/ subdirectory, users can define in the ansible/inventory/group_vars/debops_all_hosts/keyring.yml file:

keyring__local_path: '{{ inventory_dir | realpath + "/../keyring" }}'

This will tell the role to look for the key files in a ansible/keyring/ directory, relative to the Ansible inventory.

Each key file in the directory should be an ASCII-armored file, named using a specific format:

0xFINGERPRINT.asc

At runtime the role will check the specified directory for any GPG key files and will create a list which will be used to determine if a GPG key with a given ID is available locally. If a key is found, installation from the local key store will take precedence over other network-based methods.

  Example inventory

The role is included by default in the bootstrap-ldap.yml and the common.yml playbook, therefore you don't need to do anything to enable it.

  Example playbook

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

---
- name: Manage APT and GPG keyrings
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_all_hosts', 'debops_service_keyring' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  roles:
    - role: keyring
      tags: [ 'role::keyring', 'skip::keyring' ]

  Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::keyring
    Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.

  Other resources

List of other useful resources related to the debops.keyring Ansible role:

•   Manual pages: apt-secure(8) <https://manpages.debian.org/apt-secure(8)>, apt-key(8) <https://manpages.debian.org/apt-key(8)>, gpg(1) <https://manpages.debian.org/gpg(1)>

•   SecureApt <https://wiki.debian.org/SecureApt> page on Debian Wiki

•   Documentation of the Ansible ansible.builtin.apt_key module <https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_key_module.html>

DEFAULT VARIABLE DETAILS

Some of debops.keyring default variables have more extensive configuration than simple strings or lists, here you can find documentation and examples for them.

  keyring__dependent_apt_auth_files

The keyring__dependent_apt_auth_files list can be used to create and manage /etc/apt/auth.conf.d/ configuration files which caontain authentication credentials required by specific APT repositories. The format and more details about these files can be found in apt_auth.conf(5) <https://manpages.debian.org/apt_auth.conf(5)> manual page. The debops.reprepro role can be used to create APT repositories that require authentication.

This functionality is also available in the debops.apt role for use via the Ansible inventory. See apt__auth_files for more details.

  Examples

Provide credentials for a private APT repository, with password stored in the secret/ directory managed by the debops.secret role. The APT repository is managed by the debops.reprepro role which uses the debops.nginx role to manage the authentication credentials.

keyring__dependent_apt_auth_files:
  - name: 'private_repo'
    machine: 'https://repo.example.org/debian'
    login: 'username'
    password: '{{ lookup("password", secret + "/credentials/repo"
                                            + "/nginx/htpasswd"
                                            + "/apt_access/username") }}'

  Syntax

THe variables are defined as a list of YAML dictionaries .Each configuration entry defines a separate file in the /etc/apt/auth.conf.d/ directory. The state and contents of the file are specified using specific parameters:

name
    Required. Name of the configuration file with authentication credentials, can contain .conf suffix which will be stripped. Entries with the same name parameter are merged together using Universal Configuration and can affect each other in order of appearance.

machine
    Required. The URL of the APT repository that requires the following credentials.

login
    Required. The username expected by the APT repository during HTTP Basic Authentication.

password
    Required. The password expected by the APT repository during HTTP Basic Authentication. It can be stored in the secret/ directory and retrieved from there if needed.

state
    Optional. If not defined or present, a given configuration file will created on the host. If absent, a given configuration file will be removed from the host. If ignore, a given entry will not be evaluated during role execution.

comment
    Optional. String or YAML text block with additional comments included in the generated configuration file.

  keyring__dependent_apt_keys

This variable defines a list of GPG keys which should be present (or absent) in the host's APT keyring <https://wiki.debian.org/SecureApt>, used to verify signatures of the Debian/Ubuntu package lists. It is meant to be used by other Ansible roles via the role-dependent variables.

  Examples

Using the debops.nginx role, ensure that the nginx.org <https://nginx.org/en/linux_packages.html> upstream APT key is present in the APT keyring. If the key is not available in the local key store, it will be downloaded from the keyserver specified in the keyring__keyserver variable:

# Role: debops.nginx/defaults/main.yml
nginx__keyring__dependent_apt_keys:
  - '573B FD6B 3D8F BC64 1079  A6AB ABF5 BD82 7BD9 BF62'

# Playbook: nginx.yml
- hosts: [ 'debops_service_nginx' ]
  roles:
    - role: debops.keyring
      keyring__dependent_apt_keys:
        - '{{ nginx__keyring__dependent_apt_keys }}'
    - role: debops.nginx

Using the debops.nginx role, ensure that the nginx.org upstream APT key is present in the APT keyring, if support for upstream version of nginx is enabled. If the key is not available in the local key store, it will be downloaded from the specified URL. Additionally, ensure that the APT repository configuration is present and the cache is updated. The playbook is the same as in the previous example:

# Role: debops.nginx/defaults/main.yml
nginx__upstream: True
nginx__keyring__dependent_apt_keys:
  - id: '573B FD6B 3D8F BC64 1079  A6AB ABF5 BD82 7BD9 BF62'
    url: 'https://nginx.org/keys/nginx_signing.key'
    repo: 'deb http://nginx.org/packages/debian {{ ansible_distribution_release }} nginx'
    state: '{{ "present" if nginx__upstream | bool else "absent" }}'

Also with the debops.nginx role, install the APT GPG key in a separate keyring and tell APT to use this key only for Nginx official packages. The APT repository configuration will be stored in the /etc/apt/sources.list.d/nginx-upstream.list' configuration file (note the `>`` YAML block marker, which will fold the repository string to a single line):

nginx__keyring__dependent_apt_keys:
  - id: '573B FD6B 3D8F BC64 1079  A6AB ABF5 BD82 7BD9 BF62'
    url: 'https://nginx.org/keys/nginx_signing.key'
    keyring: '/usr/share/keyring/nginx-archive-keyring.gpg'
    repo: >
      deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg]
          http://nginx.org/packages/debian {{ ansible_distribution_release }} nginx
    filename: 'nginx-upstream'
    state: '{{ "present" if nginx__upstream | bool else "absent" }}'

There are many more real-world examples available in various DebOps roles. To find them, you can run the command in the DebOps monorepo root directory:

git grep '__keyring__dependent_apt_keys:' ansible/roles

  Syntax

The value of the keyring__dependent_apt_keys variable is a YAML list. Each list entry can be a string which represents the GPG key ID which will be imported either from the local storage, or from the configured GPG keyserver. Alternatively, list entry can be a YAML dictionary which allows a more fine-grained control over the state of the GPG key and its source.

The YAML dictionaries are defined using specific parameters:

id  The GPG key fingerprint which is defined by this entry. It can be specified with spaces, which will be automatically removed when necessary. This parameter is not required if the repo parameter is specified.

data
    Optional. The contents of the GPG key specified as a YAML text block (the key should be armored). If not specified, and the GPG key is found in the configured local key store, the role will try to lookup the key data from the file. If the key is not available in the local key store, the role will try to use the configured GPG keyserver to retrieve it, unless url or keybase parameters are specified.

url Optional. The URL where a given GPG key can be found. The id parameter still needs to be specified for the apt_key Ansible module to work as expected.

keybase
    Optional. The name of the Keybase <https://keybase.io/> profile which should be used to lookup the key using the Keybase API <https://keybase.io/docs/api/1.0/call/user/pgp_keys.asc>. If the url parameter is specified, it will override the keybase parameter.

keyring
    Optional. Absolute path for the keyring where the GPG key should be stored. If omitted, the key will be stored in the system-wide keyring (/etc/apt/trusted.gpg).

keyserver
    Optional. Override the default GPG keyserver URL specified in the keyring__keyserver variable.

state
    Optional. If not specified or present, the GPG key will be added to the APT keyring. If absent, the key will be removed from the APT keyring. The same state will be applied to the APT repository, if the repo parameter is specified.

repo
    The sources.list(5) <https://manpages.debian.org/sources.list(5)> entry which defines an APT repository. This parameter can be specified with the GPG key id of the APT repository, or as standalone, to more efficiently configure APT (for example if multiple GPG keys are configured at once).

extrepo
    Optional. Specify the name of the APT source configured by the extrepo external repository manager (see debops.extrepo for more details). If the specified APT source is already enabled, the debops.keyring role will skip APT-related tasks (GPG key managemnt, APT repository configuration) to avoid creating duplicate entries.

filename
    Optional. The name of the configuration file in the /etc/sources.list.d/ directory which will be used to store the APT repository configuration.

  keyring__dependent_gpg_keys

The keyring__dependent_gpg_keys variable can be used to manage GPG keys on the UNIX accounts. If an account is not defined, the root account GPG keyring will be used by default. The GPG keys are useful to verify signatures of the git commits or tags, or other files downloaded over the network with external GPG signatures.

  Examples

Using the debops.yadm Ansible role, prepare the GPG key of the yadm upstream author to verify his GPG signature on the specific git tag checked out from the repository, but only when the installation from upstream is enabled. The GPG key will be added to the root UNIX account GPG keyring:

# Role: debops.yadm/defaults/main.yml
yadm__upstream_enabled: True
yadm__upstream_gpg_id: '31B9 62F7 CC57...'
yadm__keyring__dependent_gpg_keys:
  - id: '{{ yadm__upstream_gpg_id }}'
    state: '{{ "present" if yadm__upstream_enabled | bool else "absent" }}'

# Playbook: yadm.yml
- hosts: [ 'debops_service_yadm' ]
  roles:
    - role: debops.keyring
      keyring__dependent_gpg_keys:
        - '{{ yadm__keyring__dependent_gpg_keys }}'
    - role: debops.yadm

NOTE: The functionality below will be implemented at a later date.

Extract GPG key ids from the debops.golang configuration and install them on the UNIX account used by the role to build the docker-registry Go binary, which is then used by the debops.docker_registry role. The GPG keys will be used to verify the git tags of the downloaded repositories:

# Role: debops.docker_registry/defaults/main.yml
docker_registry__golang__dependent_packages:
  - name: 'docker-registry'
    apt_packages: [ 'docker-registry' ]
    upstream: True
    gpg: '8C7A 111C 2110 5794 B0E8  A27B F58C 5D0A 4405 ACDB'
    git:
      - repo: 'https://github.com/docker/distribution'
        version: 'v2.7.1'
        build_script: |
          make clean binaries
    binaries:
      - src: 'github.com/docker/distribution/bin/registry'
        dest: 'docker-registry'
        notify: [ 'Restart docker-registry' ]

# Role: debops.golang/defaults/main.yml
golang__user: '_golang'
golang__group: '_golang'
golang__home: '/var/local/_golang'
golang__combined_packages: '{{ golang__dependent_packages | d([]) }}'
golang__keyring__dependent_gpg_user: '{{ golang__user }}'
golang__keyring__dependent_gpg_keys:
  - user: '{{ golang__user }}'
    group: '{{ golang__group }}'
    home: '{{ golang__home }}'
  - '{{ golang__combined_packages | debops.debops.parse_kv_items
        | selectattr("gpg", "defined") | selectattr("state", "equalto", "present")
        | map(attribute="gpg") | list }}'

# Playbook: docker_registry.yml
- hosts: [ 'debops_service_docker_registry' ]
  roles:
    - role: debops.keyring
      keyring__dependent_gpg_user: '{{ golang__keyring__dependent_gpg_user }}'
      keyring__dependent_gpg_keys:
        - '{{ golang__keyring__dependent_gpg_keys }}'
    - role: debops.golang
      golang__dependent_packages:
        - '{{ docker_registry__golang__dependent_packages }}'
    - role: debops.docker_registry

There are many more real-world examples available in various DebOps roles. To find them, you can run the command in the DebOps monorepo root directory:

git grep '__keyring__dependent_gpg_keys:' ansible/roles

  Syntax

The value of the keyring__dependent_gpg_keys variable is a YAML list. Each list entry can be a string which represents the GPG key ID which will be imported either from the local storage, or from the configured GPG keyserver. Alternatively, list entry can be a YAML dictionary which allows a more fine-grained control over the state of the GPG key and its source.

The YAML dictionaries are defined using specific parameters:

id  The GPG key fingerprint which is defined by this entry. It can be specified with spaces, which will be automatically removed when necessary. This parameter is not required if the user parameter is specified.

data
    Optional. The contents of the GPG key specified as a YAML text block (the key should be armored). If not specified, and the GPG key is found in the configured local key store, the role will try to lookup the key data from the file. If the key is not available in the local key store, the role will try to use the configured GPG keyserver to retrieve it, unless url or keybase parameters are specified.

url Optional. The URL where a given GPG key can be found.

keybase
    Optional. The name of the Keybase <https://keybase.io/> profile which should be used to lookup the key using the Keybase API <https://keybase.io/docs/api/1.0/call/user/pgp_keys.asc>. If the url parameter is specified, it will override the keybase parameter.

keyserver
    Optional. Override the default GPG keyserver URL specified in the keyring__keyserver variable.

state
    Optional. If not specified or present, the GPG key will be added to the GPG keyring of a specified UNIX account, or the root account. If absent, the key will be removed from the GPG keyring. If ignore, a given configuration entry will not be evaluated by the role.

create_user
    Optional, boolean. If not specified or True, and the user parameter is present, the configured UNIX account will be created to allow GPG keyring management. If False, the role will not try to create an UNIX account; this might be useful if the account is already created in non-local user database, like LDAP.

user
    A name of the UNIX account to create by the debops.keyring role, so that its GPG keyring can be correctly created and accessed. If this parameter is specified, you can omit the id parameter to only create the UNIX account.

group
    Optional. A name of the primary UNIX group of the created UNIX account. If not specified, the UNIX group will have the same name as the UNIX account.

home
    Optional. The absolute path of the home directory of the created UNIX account. If not specified, a home directory will be created in the /home/ directory by default.

system
    Optional, boolean. If not specified or True, the created UNIX account and group will be "system" account and group, with UID/GID < 1000. If False, the UNIX account and group will be "normal" account and group, with UID/GID > 1000.

AUTHOR
Maciej Delmanowski

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