-
Notifications
You must be signed in to change notification settings - Fork 108
Centralized SSH key management #1673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
0075f27
b4f375e
57944c6
09d3c7f
b59df72
d2074f4
a845b2e
ea52293
c6f1909
bbc6f6e
2e84023
fcf4910
fd21843
bb0bf88
78f89ec
4b83cf4
5e46b50
7b560f1
3f4a611
d81a23b
e57454d
7231e1d
5bc6c69
d0fda49
2daca36
92d4c70
1db9d3a
a07df90
46e63d5
7a3378f
a79e928
a5930e0
03e7462
763c8b4
5a02de0
2d1d251
a32073b
d591222
4a1de84
028691d
69e64b9
f27b481
adb2ffc
af64aac
7adac48
2a8b233
263307b
b823dd6
0a2fad3
508957b
d38b28f
3b27073
d4931a7
f7916b7
d3278fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,112 @@ | ||||||
| --- | ||||||
|
|
||||||
| # I need someone to complete this list bellow because Im probably missing most of them | ||||||
| ssh_roles: | ||||||
| - name: admin | ||||||
| hosts: all | ||||||
| users: | ||||||
| - centos | ||||||
| - stats | ||||||
| - galaxy | ||||||
| - root # can be omitted for now, centos can `sudo su` | ||||||
|
|
||||||
| - name: stats | ||||||
| hosts: | ||||||
| - sn09 | ||||||
| - sn06 | ||||||
| users: | ||||||
| - stats | ||||||
|
|
||||||
| - name: galaxy | ||||||
| hosts: | ||||||
| - sn09 | ||||||
| - sn06 | ||||||
| users: | ||||||
| - galaxy | ||||||
|
|
||||||
| ssh_users: | ||||||
| - user: galaxy | ||||||
| key: | ||||||
| - "{{ galaxy_user_public_key }}" | ||||||
| roles: | ||||||
| - admin | ||||||
|
|
||||||
| - user: bgruening | ||||||
| key: | ||||||
| - https://github.com/bgruening.keys | ||||||
| roles: | ||||||
| - admin | ||||||
|
|
||||||
| - user: mira-miracolu | ||||||
| key: | ||||||
| - https://github.com/mira-miracolu.keys | ||||||
| roles: | ||||||
| - admin | ||||||
|
|
||||||
| - user: dominguj | ||||||
|
||||||
| - user: dominguj | |
| - user: kysrpex |
If this is referencing to GH user handles this would be @kysrpex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its more for identification purposes. Its not used in playbook (:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, this name is not even used in the playbook.
Imo this field should contain something that can be easily traced to a person and a full name would do wonders (after all, our full names are all already here https://usegalaxy-eu.github.io/people).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,3 +124,6 @@ sn12.galaxyproject.eu | |
|
|
||
| [osiris] | ||
| osiris.denbi.de ansible_ssh_user=rocky | ||
|
|
||
| [test-ssh] | ||
| sn09.galaxyproject.eu | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| --- | ||
| - name: "Check if user {{ target_user }} exists on target host" | ||
| ansible.builtin.set_fact: | ||
| user_exists: "{{ target_user in (getent_passwd_result.ansible_facts.getent_passwd | default({})).keys() }}" | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: "Get home directory for user {{ target_user }}" | ||
| ansible.builtin.set_fact: | ||
| user_home_dir: "{{ getent_passwd_result.ansible_facts.getent_passwd[target_user][4] }}" | ||
| when: user_exists | bool | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
|
|
||
| - name: "Process user {{ target_user }}" | ||
| block: | ||
| - name: "Ensure .ssh directory exists for {{ target_user }}" | ||
| become: true | ||
| ansible.builtin.file: | ||
| path: "{{ user_home_dir }}/.ssh" | ||
| state: directory | ||
| owner: "{{ target_user }}" | ||
| group: "{{ getent_passwd_result.ansible_facts.getent_passwd[target_user][2] }}" | ||
| mode: '0700' | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
|
|
||
| - name: "Manage SSH keys for {{ target_user }} (exclusive)" | ||
| become: true | ||
| ansible.posix.authorized_key: | ||
| user: "{{ target_user }}" | ||
| key: "{{ user_keys_map[target_user] | join('\n') }}" | ||
| path: "{{ user_home_dir }}/.ssh/authorized_keys" | ||
| state: present | ||
| exclusive: true | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
| when: user_keys_map[target_user] | default([]) | length > 0 | ||
|
|
||
| - name: "Ensure authorized_keys file exists even if no keys (for {{ target_user }})" | ||
| become: true | ||
| ansible.builtin.file: | ||
| path: "{{ user_home_dir }}/.ssh/authorized_keys" | ||
| state: touch | ||
| owner: "{{ target_user }}" | ||
| group: "{{ getent_passwd_result.ansible_facts.getent_passwd[target_user][2] }}" | ||
| mode: '0600' | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
| when: user_keys_map[target_user] | default([]) | length == 0 | ||
|
|
||
| when: | ||
| - user_exists | bool | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: "Warning for non-existent user {{ target_user }}" | ||
| ansible.builtin.debug: | ||
| msg: "Warning: User {{ target_user }} does not exist on {{ target_host | default(inventory_hostname) }}, skipping" | ||
| when: not (user_exists | bool) | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| --- | ||
| - name: "Process role: {{ current_role.name }}" | ||
| ansible.builtin.debug: | ||
| msg: "Processing role {{ current_role.name }} for host {{ target_host | default(inventory_hostname) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: "Collect SSH keys for role: {{ current_role.name }}" | ||
| ansible.builtin.set_fact: | ||
| role_keys: >- | ||
| {{ ssh_users | ||
| | selectattr('roles', 'contains', current_role.name) | ||
| | map(attribute='key') | ||
| | flatten | ||
| | reject('match', '^https?://') | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | list }} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: "Collect SSH keys from URLs for role: {{ current_role.name }}" | ||
| ansible.builtin.set_fact: | ||
| role_url_keys: >- | ||
| {{ ssh_users | ||
| | selectattr('roles', 'contains', current_role.name) | ||
| | map(attribute='key') | ||
| | flatten | ||
| | select('match', '^https?://') | ||
| | list }} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
|
|
||
|
|
||
|
|
||
| - name: "Fetch keys from URLs for role: {{ current_role.name }}" | ||
| ansible.builtin.set_fact: | ||
| fetched_keys: >- | ||
| {{ fetched_keys | default([]) + ( | ||
| lookup('url', item) | ||
| | default('') | ||
| | replace(',', '\n') | ||
| | split('\n') | ||
| | map('trim') | ||
| | reject('equalto', '') | ||
| | select('match', '^(ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-|[email protected]|sk-ecdsa-sha2-)') | ||
| | list | ||
| ) }} | ||
| loop: "{{ role_url_keys | default([]) | unique }}" | ||
| when: role_url_keys | default([]) | length > 0 | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
|
|
||
|
|
||
|
|
||
| - name: "Combine all keys for role: {{ current_role.name }}" | ||
| ansible.builtin.set_fact: | ||
| all_role_keys: >- | ||
| {{ (role_keys | default([])) + (fetched_keys | default([])) | ||
| | map('trim') | ||
| | reject('equalto', '') | ||
| | unique | ||
| | list }} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
|
|
||
|
|
||
|
|
||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - name: "Add role keys to each target user in user_keys_map" | ||
| ansible.builtin.set_fact: | ||
| user_keys_map: >- | ||
| {{ user_keys_map | combine({ | ||
| item: (user_keys_map.get(item, []) + all_role_keys) | unique | list | ||
| }) }} | ||
| loop: "{{ current_role.users }}" | ||
| when: | ||
| - current_role.users is defined | ||
| - current_role.users | length > 0 | ||
| - all_role_keys | length > 0 | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: "Reset variables for next role" | ||
| ansible.builtin.set_fact: | ||
| role_keys: [] | ||
| role_url_keys: [] | ||
| fetched_keys: [] | ||
| all_role_keys: [] | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #SPDX-License-Identifier: MIT-0 | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| --- | ||
| - name: Get passwd database on target to find user home directories | ||
| ansible.builtin.getent: | ||
| database: passwd | ||
| register: getent_passwd_result | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Find applicable SSH roles for current target host | ||
| ansible.builtin.set_fact: | ||
| applicable_roles: >- | ||
| {{ ssh_roles | ||
| | selectattr('hosts', 'contains', target_host | default(inventory_hostname)) | ||
| | list }} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Initialize user_keys_map | ||
| ansible.builtin.set_fact: | ||
| user_keys_map: {} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Collect all target users from applicable roles | ||
| ansible.builtin.set_fact: | ||
| all_target_users: >- | ||
| {{ applicable_roles | ||
| | map(attribute='users') | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | flatten | ||
| | unique | ||
| | list }} | ||
| delegate_to: "{{ target_host | default(omit) }}" | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Process each applicable role to collect keys per user | ||
| ansible.builtin.include_tasks: collect_role_keys.yml | ||
| loop: "{{ applicable_roles }}" | ||
| loop_control: | ||
| loop_var: current_role | ||
| when: applicable_roles | length > 0 | ||
|
|
||
| - name: Apply collected keys to each target user | ||
| ansible.builtin.include_tasks: apply_keys_to_user.yml | ||
| loop: "{{ all_target_users }}" | ||
| loop_control: | ||
| loop_var: target_user | ||
| when: | ||
| - all_target_users | length > 0 | ||
| - target_user in user_keys_map | ||
gsaudade99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - user_keys_map[target_user] | length > 0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| # ansible-playbook test-ssh.yml --check --diff | ||
| # it should output the changes to the authorized_keys file | ||
| - hosts: localhost | ||
| gather_facts: false | ||
| vars_files: | ||
| - group_vars/ssh.yml | ||
|
|
||
| pre_tasks: | ||
| - name: Get all hosts matching the pattern | ||
| delegate_to: localhost | ||
| ansible.builtin.set_fact: | ||
| matched_hosts: "{{ query('inventory_hostnames', 'test-ssh') }}" | ||
| run_once: true | ||
|
|
||
| tasks: | ||
| - name: Run ssh-manager role for each matched host | ||
| ansible.builtin.include_role: | ||
| name: ssh-manager | ||
| loop: "{{ matched_hosts }}" | ||
| loop_control: | ||
| loop_var: target_host | ||
kysrpex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.