From e8376ee112a35a1722dad3ead1e100089db132d2 Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 20:10:12 +0400 Subject: [PATCH 1/7] Add a task for optionally configuring the `AllowUsers` directive --- roles/sshd/tasks/main.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml index d35222a..ab6d06d 100644 --- a/roles/sshd/tasks/main.yml +++ b/roles/sshd/tasks/main.yml @@ -21,3 +21,12 @@ regexp: '^#?LogLevel' line: 'LogLevel VERBOSE' validate: sshd -f %s -t + +- name: "Configure AllowUsers" + when: sshd_allow_users is defined + notify: Restart sshd + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?\s*AllowUsers\s+' + line: "AllowUsers {{ sshd_allow_users }}" + validate: sshd -f %s -t From 71a02a6035f13127a4422e6e686a038ef60282da Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 20:13:56 +0400 Subject: [PATCH 2/7] Rework Molecule tests to support checking the `AllowUsers` directive --- roles/sshd/molecule/default/converge.yml | 1 + roles/sshd/molecule/default/verify.yml | 93 +++++++++++++----------- 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/roles/sshd/molecule/default/converge.yml b/roles/sshd/molecule/default/converge.yml index bea06f8..bb22a32 100644 --- a/roles/sshd/molecule/default/converge.yml +++ b/roles/sshd/molecule/default/converge.yml @@ -3,3 +3,4 @@ hosts: all roles: - role: "genlab.common.sshd" + sshd_allow_users: "testusr" diff --git a/roles/sshd/molecule/default/verify.yml b/roles/sshd/molecule/default/verify.yml index 29b09d7..2e6f948 100644 --- a/roles/sshd/molecule/default/verify.yml +++ b/roles/sshd/molecule/default/verify.yml @@ -5,20 +5,36 @@ gather_facts: false any_errors_fatal: true - tasks: + pre_tasks: - name: Gather service facts ansible.builtin.service_facts: + - name: Set up users and keys for testing + loop: + - testusr + - testusr_notallowed + loop_control: + loop_var: username + ansible.builtin.include_tasks: mkuser.yml + + tasks: - name: Ensure sshd is running + vars: + sshd_state: "{{ ansible_facts.services['ssh.service'].state | default('unknown') }}" ansible.builtin.assert: - that: - - ansible_facts.services['ssh.service'].state == 'running' + that: sshd_state == 'running' + success_msg: "OK, sshd state: '{{ sshd_state }}'" + fail_msg: "FAIL, sshd state: '{{ sshd_state }}'" - name: Ensure sshd_config syntax is OK - ansible.builtin.command: sshd -t -f /etc/ssh/sshd_config changed_when: false + ansible.builtin.command: + cmd: sshd -t -f /etc/ssh/sshd_config - name: Ensure main parameteres are applied + args: + executable: /bin/bash + changed_when: false ansible.builtin.shell: | set -o pipefail ; sshd -T | egrep -i ' @@ -27,50 +43,45 @@ ^passwordauthentication no| ^pubkeyauthentication yes ' - args: - executable: /bin/bash - changed_when: false - name: Get sshd_config stats + register: sshd_conf ansible.builtin.stat: path: /etc/ssh/sshd_config - register: sshd_conf - name: Ensure sshd_config file is secure + vars: + uid: "{{ sshd_conf.stat.uid }}" + gid: "{{ sshd_conf.stat.gid }}" + mode: "{{ sshd_conf.stat.mode }}" ansible.builtin.assert: that: - - sshd_conf.stat.uid == 0 - - sshd_conf.stat.gid == 0 - - sshd_conf.stat.mode == '0600' + - uid == '0' + - gid == '0' + - mode == '0600' + success_msg: "OK, sshd_config file uid: '{{ uid }}', gid: '{{ gid }}', mode: '{{ mode }}'" + fail_msg: "FAIL, sshd_config file uid: '{{ uid }}', gid: '{{ gid }}', mode: '{{ mode }}'" - - name: Create test user - ansible.builtin.user: - name: test - create_home: true - shell: /bin/bash - - - name: Create .ssh directory - ansible.builtin.file: - path: /home/test/.ssh/ - state: directory - mode: '0700' - owner: test - group: test - - - name: Generate ssh keys - community.crypto.openssh_keypair: - path: /home/test/.ssh/id_rsa - owner: test - group: test - mode: '0600' - register: sshd_key_result - - - name: Put public key to test user - ansible.posix.authorized_key: - user: test - key: "{{ sshd_key_result.public_key }}" - state: present - - - name: Test ssh connection - ansible.builtin.command: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /home/test/.ssh/id_rsa test@localhost hostname + - name: Test ssh connection with an allowed user changed_when: false + ansible.builtin.command: + cmd: >- + ssh + -o StrictHostKeyChecking=no + -o UserKnownHostsFile=/dev/null + -i /home/testusr/.ssh/id_rsa + testusr@localhost + hostname + + - name: Test ssh connection with a disallowed user + register: result + changed_when: false + failed_when: result.rc == 0 + ansible.builtin.command: + cmd: >- + ssh + -o StrictHostKeyChecking=no + -o UserKnownHostsFile=/dev/null + -i /home/testusrnotallowed/.ssh/id_rsa + testusrnotallowed@localhost + hostname From dfa5ae3a19a51b9a737880653fd1fd6cb7d147b9 Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 21:04:43 +0400 Subject: [PATCH 3/7] Fix a test task --- roles/sshd/molecule/default/verify.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/sshd/molecule/default/verify.yml b/roles/sshd/molecule/default/verify.yml index 2e6f948..063c31e 100644 --- a/roles/sshd/molecule/default/verify.yml +++ b/roles/sshd/molecule/default/verify.yml @@ -74,9 +74,9 @@ hostname - name: Test ssh connection with a disallowed user - register: result + register: sshd_verify_conn_result changed_when: false - failed_when: result.rc == 0 + failed_when: sshd_verify_conn_result.rc == 0 ansible.builtin.command: cmd: >- ssh From 1d0676f71ba00e4cfc61bb9b24ce0fbc70b34fd9 Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 21:05:16 +0400 Subject: [PATCH 4/7] Add support for `AllowGroups` --- roles/sshd/tasks/main.yml | 12 +++--------- roles/sshd/tasks/whitelists.yml | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 roles/sshd/tasks/whitelists.yml diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml index ab6d06d..f567900 100644 --- a/roles/sshd/tasks/main.yml +++ b/roles/sshd/tasks/main.yml @@ -14,6 +14,9 @@ - name: "Configure additional restrictions" ansible.builtin.include_tasks: "restrictions.yml" +- name: "Configure whitelists" + ansible.builtin.include_tasks: "whitelists.yml" + - name: "Log at VERBOSE level" notify: Restart sshd ansible.builtin.lineinfile: @@ -21,12 +24,3 @@ regexp: '^#?LogLevel' line: 'LogLevel VERBOSE' validate: sshd -f %s -t - -- name: "Configure AllowUsers" - when: sshd_allow_users is defined - notify: Restart sshd - ansible.builtin.lineinfile: - path: /etc/ssh/sshd_config - regexp: '^#?\s*AllowUsers\s+' - line: "AllowUsers {{ sshd_allow_users }}" - validate: sshd -f %s -t diff --git a/roles/sshd/tasks/whitelists.yml b/roles/sshd/tasks/whitelists.yml new file mode 100644 index 0000000..3952302 --- /dev/null +++ b/roles/sshd/tasks/whitelists.yml @@ -0,0 +1,18 @@ +--- +- name: "Configure AllowUsers" + when: sshd_allow_users is defined + notify: Restart sshd + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?\s*AllowUsers\s+' + line: "AllowUsers {{ sshd_allow_users }}" + validate: sshd -f %s -t + +- name: "Configure AllowGroups" + when: sshd_allow_groups is defined + notify: Restart sshd + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?\s*AllowGroups\s+' + line: "AllowGroups {{ sshd_allow_groups }}" + validate: sshd -f %s -t From 15d3ca8a70b733ef2bebdec14057cad1f103ad9c Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 21:20:01 +0400 Subject: [PATCH 5/7] Add a helper `pre_tasks` unit for Molecule Verify --- roles/sshd/molecule/default/mkuser.yml | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 roles/sshd/molecule/default/mkuser.yml diff --git a/roles/sshd/molecule/default/mkuser.yml b/roles/sshd/molecule/default/mkuser.yml new file mode 100644 index 0000000..889f87f --- /dev/null +++ b/roles/sshd/molecule/default/mkuser.yml @@ -0,0 +1,28 @@ +--- +- name: "Create user account: {{ username }}" + ansible.builtin.user: + name: "{{ username }}" + create_home: true + shell: /bin/bash + +- name: "Create .ssh directory: {{ username }}" + ansible.builtin.file: + path: "/home/{{ username }}/.ssh/" + state: directory + mode: '0700' + owner: "{{ username }}" + group: "{{ username }}" + +- name: "Generate ssh keys: {{ username }}" + community.crypto.openssh_keypair: + path: "/home/{{ username }}/.ssh/id_rsa" + owner: "{{ username }}" + group: "{{ username }}" + mode: '0600' + register: sshd_key_result + +- name: "Put public key to into the authorized_keys: {{ username }}" + ansible.posix.authorized_key: + user: "{{ username }}" + key: "{{ sshd_key_result.public_key }}" + state: present From 63102b87ed6bc04d2ec17f8cd23c426a78591e71 Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Mon, 18 May 2026 21:36:12 +0400 Subject: [PATCH 6/7] Update the list of excluded paths for `ansible-lint` --- .ansible-lint | 1 + 1 file changed, 1 insertion(+) diff --git a/.ansible-lint b/.ansible-lint index 548eab6..3766b2b 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -12,3 +12,4 @@ exclude_paths: # ansible-lint thinks they're playbooks so gives errors, but they're not - roles/rustdesk/molecule/default/client-binary-existance.yml - roles/borg_server/molecule/default/secrets.yaml + - roles/sshd/molecule/default/mkuser.yaml From 05c5041086b05b2480a36064bb3583ceb84a3d5b Mon Sep 17 00:00:00 2001 From: Alexander Gorelyshev Date: Tue, 19 May 2026 00:08:21 +0400 Subject: [PATCH 7/7] Fix extension --- .ansible-lint | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ansible-lint b/.ansible-lint index 3766b2b..0572c35 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -12,4 +12,4 @@ exclude_paths: # ansible-lint thinks they're playbooks so gives errors, but they're not - roles/rustdesk/molecule/default/client-binary-existance.yml - roles/borg_server/molecule/default/secrets.yaml - - roles/sshd/molecule/default/mkuser.yaml + - roles/sshd/molecule/default/mkuser.yml