Hi James,
Thanks for your help! You put me on the right track. Here's what I ended up doing (in case someone else finds this useful).
First, for DRY's sake, I collected the absolute paths to the apt keys in group_vars/all to make them "global" and role-independent, in a form that could be consumed using with_subelements:
---
apt_keys_by_role:
- role: common
keyfiles:
- path: "{{ inventory_dir }}/roles/common/files/apt_keys"
filename: some_common_key.asc
pub: 90FDDD2E
- path: "{{ inventory_dir }}/roles/common/files/apt_keys"
filename: some_other_common_key.asc
pub: D88E42B4
- role: rabbitmq
keyfiles:
- path: "{{ inventory_dir }}/roles/rabbitmq/files/apt_keys"
filename: some_rabbitmq_key.asc
pub: 056E8E56
On the server, I have /etc/ansible/facts.d/installed_apt_keys.fact, a bash script that takes the output of apt-key list and transforms the pub values contained within to a JSON list. (Script omitted here, left as an exercise for the reader.)
Since (AFAIK, based on Googling) there's no way for a task to know what are the currently active roles, I also had to create a custom list variable for it and place it inside my hosts-to-roles mapping files. This is something that I hope future versions of Ansible will address by making a variable called e.g. role_names available to tasks, just like group_names already is. Here is webservers.yml as an example:
---
- hosts: webservers
roles:
- common
- rabbitmq
- web
# No access to current role names without specifying them as a variable
vars:
role_names:
- common
- rabbitmq
- web
Finally, in roles/common/tasks/main.yml I copy the key files to the target host, add them with apt_key and then remove them (since apt_key doesn't transfer the file parameters over, they need to be on the server before running it):
# copying to /tmp omitted, same logic as below
- name: add apt keys from /tmp
sudo: true
apt_key: file="/tmp/{{ item.1.filename }}"
when: "'{{ item.0.role }}' in role_names and '{{ item.1.pub }}' not in ansible_local.installed_apt_keys.key_list"
with_subelements:
- apt_keys_by_role
- keyfiles
# removal from /tmp omitted, same logic as above
The solution is not quite as clean as I'd hope it to be, but it's the best effort I've managed to piece together so far given Ansible's current limitations (and those of my Ansible knowhow).