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).
The way I solved this was to pass an array of filenames in a variable to my
user-account
role. The role then gets the contents of each of these files, appends them together into a newline-separated string, then finally sets this value to be the ssh-key for the new user..
The playbook file:
.
The role definition for
user-account
:I found this question in the list of unanswered questions and did a little research. It looks like the diff functionality was added to the authorized_keys module in ansible not long after your question. The commit was merged early in 2017 and appear to have been included in version 2.3 and later. It looks like your third option should work now, but without your key setup, I can't be sure.
https://github.com/ansible/ansible/commit/b0b7a636d8930a2c7192ea83ff890e4313aaf4d9#diff-e50c31b8374987e7c9dd4795d7f2e89f
https://github.com/ansible/ansible/pull/19277