Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0075f27
first draft
gsaudade99 Oct 15, 2025
b4f375e
add missing role
gsaudade99 Oct 15, 2025
57944c6
refactor role-based access
gsaudade99 Oct 20, 2025
09d3c7f
adding quotes to user galaxy key
gsaudade99 Oct 20, 2025
b59df72
hardned pitfall + more changes related to the conversation
gsaudade99 Oct 22, 2025
d2074f4
fix task name
gsaudade99 Oct 22, 2025
a845b2e
Update group_vars/ssh.yml
gsaudade99 Oct 24, 2025
ea52293
Update group_vars/ssh.yml
gsaudade99 Oct 24, 2025
c6f1909
Rename playbook test-ssh.yml to all.yml
kysrpex Oct 27, 2025
bbc6f6e
Apply `ssh-manager` role to all hosts
kysrpex Oct 27, 2025
2e84023
Use a folder to store group vars that apply to all hosts
kysrpex Oct 27, 2025
fcf4910
Move SSH keys manager vars file to group_vars/all/ssh-keys.yml
kysrpex Oct 27, 2025
fd21843
Use Ansible's inventory_hostnames lookup to match roles to hosts
kysrpex Oct 27, 2025
bb0bf88
Remove `delegate_to: "{{ target_host | default(omit) }}"` statements
kysrpex Oct 27, 2025
78f89ec
Use `~` to refer to the user's home directory when applying SSH keys
kysrpex Oct 27, 2025
4b83cf4
revert role base access to user base access
gsaudade99 Oct 31, 2025
5e46b50
migrate to j2 and dict
gsaudade99 Nov 3, 2025
7b560f1
Revert changes to .gitignore
kysrpex Nov 3, 2025
3f4a611
Merge branch 'master' into feat/ssh-key-managment
kysrpex Nov 3, 2025
d81a23b
rm ssh_unix_users + skip users wihtout authorized_keys
gsaudade99 Nov 3, 2025
e57454d
Namespace variables for role `ssh-manager`
kysrpex Nov 4, 2025
7231e1d
Update group_vars/all/ssh-keys.yml
gsaudade99 Nov 4, 2025
5bc6c69
Update group_vars/all/ssh-keys.yml
gsaudade99 Nov 4, 2025
d0fda49
Update group_vars/all/ssh-keys.yml
gsaudade99 Nov 4, 2025
2daca36
Update group_vars/all/ssh-keys.yml
gsaudade99 Nov 4, 2025
92d4c70
Update group_vars/all/ssh-keys.yml
gsaudade99 Nov 4, 2025
1db9d3a
migrate ssh-manager to independent repo
gsaudade99 Nov 6, 2025
a07df90
Update authorized persons and encrypt their public keys
kysrpex Nov 10, 2025
46e63d5
Merge branch 'master' into feat/ssh-key-managment
kysrpex Nov 10, 2025
7a3378f
Update usegalaxy_eu.ssh_manager to version 0.0.2
kysrpex Nov 10, 2025
a79e928
Merge remote-tracking branch 'gsaudade99/feat/ssh-key-managment' into…
kysrpex Nov 10, 2025
a5930e0
Remove operator UNIX user from authorized persons
kysrpex Nov 11, 2025
03e7462
Use branch `shared_home_directory` of usegalaxy_eu.ssh_manager tempor…
kysrpex Nov 11, 2025
763c8b4
Revert "Use branch `shared_home_directory` of usegalaxy_eu.ssh_manage…
kysrpex Nov 11, 2025
5a02de0
Trust SSH host keys of both Jenkins workers
kysrpex Nov 14, 2025
2d1d251
Verify the usegalaxy.eu SSH cert authority signature for ``*.bi.priva…
kysrpex Nov 14, 2025
a32073b
Verify the usegalaxy.eu SSH cert authority signature for the TPV brok…
kysrpex Nov 14, 2025
d591222
Trust sn10 SSH host key
kysrpex Nov 14, 2025
4a1de84
Trust sn12 SSH host key
kysrpex Nov 14, 2025
028691d
Trust osiris SSH host key
kysrpex Nov 14, 2025
69e64b9
Trust dnbd3-primary SSH host key
kysrpex Nov 14, 2025
f27b481
Set apps Ansible port to 8080
kysrpex Nov 27, 2025
adb2ffc
Add ubuntu UNIX user to authorized persons
kysrpex Nov 27, 2025
af64aac
Trust apps SSH host key
kysrpex Nov 27, 2025
7adac48
Remove sn05 from inventory
kysrpex Dec 4, 2025
2a8b233
Trust upload SSH host key
kysrpex Dec 4, 2025
263307b
Fix indentation for playbook all.yml
kysrpex Dec 4, 2025
b823dd6
Remove Galaxy test host from inventory
kysrpex Dec 4, 2025
0a2fad3
Remove deNBI CVMFS test host from inventory
kysrpex Dec 4, 2025
508957b
Change hostname for beacon host
kysrpex Dec 4, 2025
d38b28f
Remove telescope host from inventory
kysrpex Dec 4, 2025
3b27073
Trust beacon SSH host key
kysrpex Dec 4, 2025
d4931a7
Update group_vars/all/ssh-keys.yml
mira-miracoli Dec 4, 2025
f7916b7
Apply suggestion from @mira-miracoli
mira-miracoli Dec 4, 2025
d3278fe
Use GitHub handles for Bernd and Paul in ssh-keys.yml (and vault file)
kysrpex Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions group_vars/ssh.yml
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- user: dominguj
- user: kysrpex

If this is referencing to GH user handles this would be @kysrpex

Copy link
Contributor Author

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 (:

Copy link
Contributor

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).

key:
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINZNuF25HySp311FKtDW9lDKUGslH6PGIap1eYniaPsC [email protected]'
roles:
- admin

- user: gsaudade
key:
- '[email protected] AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIAXgFT+ynWEgCCAKepVgkSHauy+mLo+KlIGIIj0dkAXeAAAABHNzaDo= [email protected]'
roles:
- admin

- user: nate
key:
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFH54+qZEBeU5uwIeWWOViLcC509qxoRW6oN0VHRQr4r nate'
roles:
- stats
- galaxy

- user: wm75
key:
- https://github.com/wm75.keys
roles:
- galaxy

- user: videmp
key:
- 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEApcUIRRUHl0wVVXz5GX1QnHSq9+nThIKKH3fYM21LfW1n6gGvC7UiCCaDZQUbejJTq3EITbH3J6/Tji2jGAIJ6Xzn0Jf7sQ1yON/dO/75To32Jdo8YWS7XQeA7lU9heSc7FM5yKIBJN7PrpnYAveCsOE/1kkfUSsBZsqj9yyoFe/tquoVm5Y3nFZfKJv7/gszSVkzNxhHvn+0ccClRLpnFUHjqXgXHIQCm7P/9Lf7unSoYRd9Iefwgp52Lcm6AIncQvz5tdAFD2WciP4J15EFPMTKPdc6tfT5Tis/+/oNfYlsnaIGrbV5Hc2909KiYnvuvqKcrSFloXWzAdXJOxhszw== [email protected]'
- 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8/9GdD96Xfc0MavIJQEuNSIrOlaBSYkH4s5RyGhNnc8Al7x3hC7KXt/mcqyNoI1JTvrXp23aDpTr67e3Dnrp6Me7z8nyY9oIy5WHOgwG2ra1Ga8oi89MVgXPhtxvcYnk8hVfuPDmhWkgwS5ILH/7V/1hEKHcS0H7Q0pJp8EGCBDFWrxNfUWqJJuVcXb11CMnaSJX/VhD+S4g4rG01lMr696+k8eKs9y2sq9JpuUD1TNN16RYu1uVlVz8nhIPbEBsnFeKV+EYKLcSRQnjDTNjWqZHHM9NMWfK3wGvr5pfla158ZdsYQTmQtcchTsEoB+7eAQaER3XsEtuo8yQj4zbL videmp@work'
roles:
- stats

- user: paul
key:
- 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCtMvCQL1Xw/DrzO/U4nfyIL6CE63apSXHjQByWK+vWpfNkBjMh4uwQl6SzWvCn6y7tlMko1P6BG9bVDkWLLjC/kL+ds+FXDwUyLmRcfyhkortBVMWrZO3ZSSimpFugPDcfUeh+iim/Jg2CY1geVmlA9bybY8k0hGTKa5rn9KzbLCoZdsR1c9627PAefV9lr7xTHMamWsG0cIYjkOBqZM85Yw9huftUGZi1SAALjiG3k57XFswZcHrvZkE/L5Q5uU9NC0KYVapzG9PYmgU+O40Oi82PB4C6SWoOM0MG39AIS4DU7DstF3mrl2M/6crbcHIfVTB+GCQI2U9CzfvlhA6qQu+xlAc4ZX/rXeYZvNW6QtU1vvUcL95wSrPyXlqlSA6o/0T0EP8e2LG2JpNtzorcLrj010fWdpH1jY/c9ZACYNmCPuUTD/ASt5FXCqPR0WJnf4Mle10ALmghsbm7vLXQUKDcQSC4bJKpgzdFT2ocmk9jiGqCq3hivSVmR6OvHok= paul@paul-LIFEBOOK-U7410'
roles:
- stats

- user: david
key:
- 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCoWkk57x20iE5Wf0cDX3QvkJf/XxO4wqIeZIPIosK7rFcvy/SvDF/mwQk4iQrQ7qDam35NFHrFden+5zoE5HJoRVeHYhqNaItmiMNBY9CqgITCXsD2j9/6NdzIcR66uzLHDVvLlXr2hJmrNoeGTzg94+EVtQ0/BARwffAq//2WzgG4oClgYE4RqahQRXbmBygf4g4BAbEb5JnsLJ3qqnhsAgcUYyXg7/dz36QVsvoTwChMMCXDJpPyNb1+PqOKAgl7+yZQiPD0yI5zZG+iF6dsvc6Dhscpmt0nOjr4h+o97wQk3sbvq9ysXPlARqgL950H+0LtSiWnC+KEBK4KOgc83g6NynCE7zGZ9LJiKoT0mmt8BKaJKFRDVob3nlYR3/DDLEq2AkCoxYF0JFUNVta/wEF/likB61Yhsv01gNVMNcCfK9nzZVyTGNwdsFPdi4WL+KfkMgEcA0xrCtLXhkxnU8f3H8a7XcwJWr3fuSK1ndFwNxmfKlA+sRRKYBHouU8rpnC/HCxYsxF/palYxHv8KNcfGIRUBIgfgugsigzFcB5yz4lY73NiEyVEY9ZnBbbXllyX3ICoI/IboMQVUDyccRZiDAeHJ/v29pIsIihkmWIT2I1VqppXuVYgTydPM42CDBaKE7ko3p0CuZDyB2sZaS4XYUQlkRpX9ZARtcC/AQ== david'
roles:
- stats

- user: bebatut
key:
- 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9itwmMTgcRCrwjO3RCke/NWJsRb3N5lUTF5fubw/V0PlSbFDuv7IMKp5hhFfhiOuVRMoXQBHnnOWWu1xd9jDqZKXmNGHg06JtnddQ/OVprZ6Dpu2g9pZ6uc4r1As94mvpICLVK9lNHPNA60sIwTsTRVFSb1VbXALI4iuLOxPLzIxhrZ1LouK19VWetJIQ/Uq8UalfTDr1KOyQQ/ZgjBeWdD5InSOl3sbPJZhGQLqSHIi0MVxH527CMnh1PQIxiD/vqX8SK7HaKvUZIHHzz5TFrUgrw7BkfRd04UIgr1OhnMf1E413yZdeQzJQV7C1CL9MbAThXX6Ruvs0Rg3ylazpYfwDifMWvqLeRoTCDUbGx94ySO/wzer/kcjpJ27iydNo+en/hImMYz7kktf6A3BzOYxFmOQvnQ9cChP+iuk7fTiQZS7Qtkz+axNIvwCkm7Hmgt7vYizHc+OAtKmzZFTHecozjxCXs9RwynnWpToheP3ZPYgOpKc7pkUngRSjXyc= bebatut@bebatut-ThinkPad-T14-Gen-1'
roles:
- stats

- user: catherine
key:
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFH54+qZEBeU5uwIeWWOViLcC509qxoRW6oN0VHRQr4r nate'
roles:
- stats

- user: jdavcs
key:
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzm/ZHp+16Oz/5TbQkJZMC5yvp/C3OfvgOlRWqEX/Fc [email protected]'
roles:
- stats

- user: marius
key:
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINGQxOm1ZlWT4k8+wK9QXSY4Obb/kz7CR7u89XWCJcqW [email protected]'
roles:
- stats
3 changes: 3 additions & 0 deletions hosts
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,6 @@ sn12.galaxyproject.eu

[osiris]
osiris.denbi.de ansible_ssh_user=rocky

[test-ssh]
sn09.galaxyproject.eu
53 changes: 53 additions & 0 deletions roles/ssh-manager/tasks/apply_keys_to_user.yml
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) }}"

- 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

- 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)
80 changes: 80 additions & 0 deletions roles/ssh-manager/tasks/collect_role_keys.yml
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) }}"

- 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?://')
| list }}
delegate_to: "{{ target_host | default(omit) }}"

- 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) }}"



- 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) }}"

- 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) }}"
47 changes: 47 additions & 0 deletions roles/ssh-manager/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#SPDX-License-Identifier: MIT-0
---
- 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) }}"

- 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) }}"

- name: Initialize user_keys_map
ansible.builtin.set_fact:
user_keys_map: {}
delegate_to: "{{ target_host | default(omit) }}"

- name: Collect all target users from applicable roles
ansible.builtin.set_fact:
all_target_users: >-
{{ applicable_roles
| map(attribute='users')
| flatten
| unique
| list }}
delegate_to: "{{ target_host | default(omit) }}"

- 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
- user_keys_map[target_user] | length > 0
22 changes: 22 additions & 0 deletions test-ssh.yml
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
Loading