How can I manage keyring files in trusted.gpg.d with ansible playbook since apt-key is deprecated?

26.5k Views Asked by At

Before apt-key was deprecated, I was using Ansible playbooks to add and update keys in my servers. At the moment, apt-key no longer updates the keys. In few searches, I found that I need to use gpg now. However, I have many servers and I don't want to do this manually for each one of them. Is there a way to manage my keyrings with gpg with Ansible?

Here are my Ansible tasks, with deprecated apt-key:

- apt_key:
  url: "https://packages.treasuredata.com/GPG-KEY-td-agent"
  state: present

- apt_repository:
  repo: "deb http://packages.treasuredata.com/3/ubuntu/{{ ansible_distribution_release }}/ {{ ansible_distribution_release }} contrib"
  state: present
  filename: "treasure-data" # Name of the pre-compiled fluentd-agent

I tried apt-key update but it is not working for me. If a key already exists but it is expired, it doesn't update it anymore.

3

There are 3 best solutions below

0
On

Created a takeoff on the above contents that utilizes set_fact. Makes it easier to copy / paste to other needs using the same code.

Supply 3 vars and your off and running. I've inserted the sm- prefix just so I can clearly see my script put them there and not any other process.

- set_fact:
     repoid: nginx
     repo_key_url: https://nginx.org/keys/nginx_signing.key
     repo_sources_list_url: "http://nginx.org/packages/ubuntu {{ os_release_name }} nginx"

- name: nginx repo - add gpg key as asc so apparmor fix not needed
  get_url:
    url: "{{ repo_key_url }}"
    dest: /etc/apt/keyrings/sm-{{ repoid }}.asc
    mode: '0644'
    force: true

- name: nginx repo - add to sources.list.d 
  apt_repository:
    filename: sm-{{repoid}}-repository
    repo: 'deb [signed-by=/etc/apt/keyrings/sm-{{ repoid }}.asc] {{ repo_sources_list_url }}'
    state: present
4
On

In short, you need to put the GPG key with the correct extension into a separate directory that is not searched by default, and point your repository configuration at that specific file.

For more info on why you need a separate directory, see this answer to "Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead".

Warning: apt will not accept ASCII GPG keys saved with .gpg extension.

You can verify whether you have the old ASCII GPG format(.asc) or the newer binary GPG format(.gpg) via file:

# file elastic-old.gpg
elastic-old.gpg: PGP public key block Public-Key (old)

# file elastic.gpg    
elastic.gpg: PGP/GPG key public ring (v4) created Mon Sep 16 17:07:54 2013 RSA (Encrypt or Sign) 2048 bits MPI=0xd70ed6cd267c5b3e...

If your key is the old format, you can either use the .asc extension, or you can optionally de-armor it via gpg --dearmor elastic.gpg into the new binary format and use the .gpg extension.

The de-armor step is annoying for ansible automation, so I suggest you just use whatever format upstream provides as is.

On Ubuntu 22.04, there's a folder you're expected to use that is not preloaded - /etc/apt/keyrings - or you can create your own directory and use that.

As for the Ansible part, you can use get_url or file to push the GPG key onto the system, and then use apt_repository like before to add the repo, with the addition of specifying the keyring.

Using the binary GPG format with .gpg

- name: Add Example GPG key
  ansible.builtin.get_url:
    url: https://example.com/example.gpg
    dest: /etc/apt/keyrings/example.gpg
    mode: '0644'
    force: true

Or using the .asc extension if upstream still hasn't switched over yet

- name: Add Example GPG key
  ansible.builtin.get_url:
    url: https://example.com/example.gpg
    dest: /etc/apt/keyrings/example.asc
    mode: '0644'
    force: true

Then you can define your repository via apt_repository module like before.

- name: Add Example repo
  ansible.builtin.apt_repository:
    filename: example-repo
    repo: 'deb [signed-by=/etc/apt/keyrings/example.gpg] https://example.com/packages/8.x/apt stable main'

Keep in mind that apt_repository uses the old .list format instead of the new DEB822 compliant .sources format.

If you want/need to use the newer DEB822 format and you happen to be running Ansible 2.15 or newer, you should use the deb822_repository module.

If you are stuck using older Ansible core, you can template it yourself similarly to this:

tasks/main.yaml

- name: Add Elastic repo
  notify: apt update force
  ansible.builtin.template:
    src: repo.j2
    dest: /etc/apt/sources.list.d/elastic-8.x.sources
    mode: '0644'
  vars:
    repo_name: Example PPA
    repo_uris: https://example.com/packages/8.x/apt
    repo_suites: stable
    repo_components: main
    repo_signed_by: /etc/apt/keyrings/example.gpg

templates/repo.j2

X-Repolib-Name: {{ repo_name }}
Types: deb
URIs: {{ repo_uris }}
Suites: {{ repo_suites }}
{% if repo_components is defined %}
Components: {{ repo_components }}
{% endif %}
Signed-By: {{ repo_signed_by }}
1
On

To expand a bit on @geerlingguy's comment regarding using the .asc extension, this is how I ended up adding the repository for Telegraf. Take note of the use of influxdb.asc in both the get_url and apt_repository tasks.

- name: Install InfluxDB key
  get_url:
    url:  https://repos.influxdata.com/influxdb.key
    dest: /etc/apt/trusted.gpg.d/influxdb.asc

- name:  Add InfluxDB repository
  apt_repository:
    repo:  "deb [signed-by=/etc/apt/trusted.gpg.d/influxdb.asc] https://repos.influxdata.com/debian stable main"
    state: present
    update_cache: yes

- name:  Install telegraf
  package:
    name:  telegraf
    state: present

You can completely bypass the gpg --dearmor step with this method.