The Problem
I am managing a number of different servers with Ansible. Each server has multiple Linux users, such as readonly
, admin
, etc.
I also have a number of files inside my Ansible project which contain all SSH keys for a particular group of people - eg. AppDevelopersPublicKeys
, DbaPublicKeys
, etc.
Different groups of people have different access levels on different servers. Eg. on a WebServer, AppDevelopers have admin access, and DBAs might only have read access. On Database servers, vice versa.
To achieve the above, I have different Ansible roles for different types of server (eg. WebAppServer
, DatabaseServer
, etc). These roles then have variables readonly_key_files
and admin_key_files
set up against them, listing appropriate key files for the roles which should have readonly and admin access.
The ideal solution would:
- Ensure public keys are exlusive - eg. if a public key is deleted from
AppDeveloperPublicKeys
file in Ansible, servers will have this key deleted too - Only upload / change the file on the servers when something has actually changed
- Show an accurate diff of the files when using
--diff
option to run Ansible
I am using Ansible 2.2.0.0
Solutions attempted so far
None of the below works exactly as I would like:
authorized_key with_file
- authorized_key: user=readonly exclusive=no key={{item}}
with_file: {{readonly_key_files}}
- This does not meet requirement 1, as it is looping over multiple files, so
exclusive
must be set tono
authorized_key with fact
Solution as per https://github.com/ansible/ansible-modules-core/pull/4167/files
- name: "Generate developer keys from multiple files"
set_fact: dev_key_list="{{ lookup('file', item) }}"
register: dev_keys
with_items: '{{developer_key_files}}'
- name: "Merge developer keys into single list"
set_fact: dev_keys_string={{ dev_keys.results | map(attribute='ansible_facts.dev_key_list') | join('\n') }}
- authorized_key: user=readonly exclusive=yes key={{dev_keys_string}}
- This meets requirement 1, but (at least for me) does not meet requirement 2 - it seems the order of the keys generated is not deterministic, so running the playbook multiple times results in the
authorized_keys
step changing even when no keys have been added / removed from files. It also doesn't seem to meet requirement 3, as when I run with--check --diff
I cannot see exactly which lines Ansible believes are changing, it just highlights that the file will be changed.
authorized_key with_template
- authorized_key: user=readonly exclusive=no key={{item}}
with_template: {{readonly_keys.j2}}
Where readonly_keys.j2
looks like:
{% for key_file in readonly_key_files %}
{% include '/files/' ~ key_file %}
{% endfor %}
- This meets requirements 1 and 2, but again fails on requirement 3. When I run using
--check --diff
it only shows me whether or not the SSH file will be changed, not exactly which lines will be added / removed as I would expect it to.
Conclusion
Is there another way to solve this problem? It seems as though there may be an issue with using --diff
with authorized_keys
in Ansible... The only other approach I can think of is not using authorized_keys
at all, and instead managing this as a regular file / template, which should show me accurate diffs (as well as meeting requirements 1 & 2).