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

3

34

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.

Hostetler answered 23/3, 2022 at 10:6 Comment(5)
From what I read in the documentation, apt_key now uses gpg under the hood. What is your version of Ansible? If that is an old version, have you considered upgrading Ansible?Prat
Hello, I am using Ansible 2.10.17 ; I can upgrade the Ansible to be honest I didn't understand under the hood comment :(Hostetler
What I meant there is that it is not because the module is called apt_key that it uses the binary apt-key. Actually most of Ansible modules do not uses any system OS commands, but rather Python utilities, since Ansible is all about Python. See: Ansible works by connecting to your nodes and pushing out small programs, called "Ansible modules" to them. These programs are written to be resource models of the desired state of the system. Ansible then executes these modules (over SSH by default), and removes them when finished..Prat
But the notes docs.ansible.com/ansible/latest/collections/ansible/builtin/… explicitly say that "The apt-key command has been deprecated and suggests to ‘manage keyring files in trusted.gpg.d instead’. See the Debian wiki for details. This module is kept for backwards compatiblity for systems that still use apt-key as the main way to manage apt repository keys." So it looks like apt_key is not meant to be used anymore...Shea
Yes, I agree. It is not to be used anymore. I have to do the updates on expired keys manually on servers which takes toll on me... I couldn't find a new way of doing it. Any ideas would be really appreciatedHostetler
C
20

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 }}
Commodious answered 8/6, 2022 at 15:23 Comment(4)
Is there a way to dearmor the server file (example.com/example.gpg) prior to saving it to the local folder (/etc/apt/keyrings/example.gpg) with Ansible?Heuser
Just to make the above clearer: is there a way to dearmor with, or via, Ansible?Heuser
As suggested in this issue comment, you can name the dest file with a .asc extension (instead of .gpg) to make it work without an extra dearmor step.Cords
Hint: If you create the /etc/apt/keyrings directory yourself as root (maybe because your OS does not ship with it), remember to give it the "o+x" permission, as it won't work otherwise.Peanut
S
11

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.

Sheelagh answered 21/9, 2022 at 19:16 Comment(1)
R
0

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
Rummel answered 4/1, 2023 at 4:48 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.