Merge branch 'master' into role-docker-ubuntu

This commit is contained in:
Fogucoco
2025-12-18 15:29:12 +03:00
committed by GitHub
15 changed files with 326 additions and 0 deletions

View File

@@ -24,6 +24,7 @@
- [rustdesk](roles/rustdesk/README.md)
- [sftp_share](roles/sftp_share/README.md)
- [smartctl_exporter](roles/smartctl_exporter/README.md)
- [sshd](roles/sshd/README.md)
- [swapfile](roles/swapfile/README.md)
- [ufw](roles/ufw/README.md)
- [users](roles/users/README.md)

37
roles/sshd/README.md Normal file
View File

@@ -0,0 +1,37 @@
ansible-sshd
=========
Deploy a hardened sshd server
Requirements
------------
None
Role Variables
--------------
None
Dependencies
------------
None
Example Playbook
----------------
```yaml
roles:
- role: genlab.common.sshd
```
License
-------
BSD
Author Information
------------------
corvus-migratorius@proton.me

View File

@@ -0,0 +1,5 @@
---
sshd_disable_pam: false
sshd_password_auth: false
sshd_challenge_response_auth: false
sshd_gss_api_auth: false

View File

@@ -0,0 +1,7 @@
---
- name: "Restart sshd"
ansible.builtin.service:
name: ssh
state: restarted
enabled: true
daemon_reload: true

17
roles/sshd/meta/main.yml Normal file
View File

@@ -0,0 +1,17 @@
---
galaxy_info:
role_name: sshd
namespace: genlab
author: "Alexander Gorelyshev"
company: "Genlab, LLC"
description: "Deploy a hardened sshd server"
license: "MIT"
min_ansible_version: "2.1"
platforms:
- name: "Ubuntu"
versions: ["jammy", "noble"]
galaxy_tags: []
dependencies: []

View File

@@ -0,0 +1,5 @@
---
- name: Converge
hosts: all
roles:
- role: "genlab.common.sshd"

View File

@@ -0,0 +1,27 @@
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu
image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest
pre_build_image: true
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: true
provisioner:
name: ansible
verifier:
name: ansible
lint: |
set -e
yamllint .
ansible-lint .

View File

@@ -0,0 +1,76 @@
---
- name: Verify
hosts: all
gather_facts: false
any_errors_fatal: true
tasks:
- name: Gather service facts
ansible.builtin.service_facts:
- name: Ensure sshd is running
ansible.builtin.assert:
that:
- ansible_facts.services['ssh.service'].state == 'running'
- name: Ensure sshd_config syntax is OK
ansible.builtin.command: sshd -t -f /etc/ssh/sshd_config
changed_when: false
- name: Ensure main parameteres are applied
ansible.builtin.shell: |
set -o pipefail ;
sshd -T | egrep -i '
^protocol 2|
^permitrootlogin no|
^passwordauthentication no|
^pubkeyauthentication yes
'
args:
executable: /bin/bash
changed_when: false
- name: Get sshd_config stats
ansible.builtin.stat:
path: /etc/ssh/sshd_config
register: sshd_conf
- name: Ensure sshd_config file is secure
ansible.builtin.assert:
that:
- sshd_conf.stat.uid == 0
- sshd_conf.stat.gid == 0
- sshd_conf.stat.mode == '0600'
- 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
changed_when: false

View File

@@ -0,0 +1,42 @@
---
# next task requires this directory to exist for sshd -t flag
- name: Ensure /run/sshd exists
ansible.builtin.file:
path: /run/sshd
state: directory
owner: root
group: root
mode: '0755'
# NOTE: order of preference for openssh-server ed25519 -> rsa
- name: "Algorithms | enable ed25519 authentication algorithm"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^HostKey /etc/ssh/ssh_host_ed25519_key'
line: 'HostKey /etc/ssh/ssh_host_ed25519_key'
validate: sshd -f %s -t
- name: "Algorithms | enable the RSA authentication algorithm"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^HostKey /etc/ssh/ssh_host_rsa_key'
line: 'HostKey /etc/ssh/ssh_host_rsa_key'
validate: sshd -f %s -t
- name: "Algorithms | disable the ECDSA algorithm (deemed to be less safe)"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^HostKey /etc/ssh/ssh_host_ecdsa_key'
state: absent
validate: sshd -f %s -t
- name: "Algorithms | disable the DSA algorithm (considered to be defunct)"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^HostKey /etc/ssh/ssh_host_dsa_key'
state: absent
validate: sshd -f %s -t

View File

@@ -0,0 +1,31 @@
---
- name: "Authentication | Configure SSH authentication settings"
notify: Restart sshd
loop:
- { regexp: '^#?\s*PubkeyAuthentication\s+', line: 'PubkeyAuthentication yes' }
- { regexp: '^#?\s*PasswordAuthentication\s+', line: 'PasswordAuthentication {{ sshd_password_auth | ternary("yes", "no") }}' }
- { regexp: '^#?\s*PermitEmptyPasswords\s+', line: 'PermitEmptyPasswords no' }
- { regexp: '^#?\s*ChallengeResponseAuthentication\s+', line: 'ChallengeResponseAuthentication {{ sshd_challenge_response_auth | ternary("yes", "no") }}' }
- { regexp: '^#?\s*GSSAPIAuthentication\s+', line: 'GSSAPIAuthentication {{ sshd_gss_api_auth | ternary("yes", "no") }}' }
- {
regexp: '^#?\s*AuthenticationMethods\s+',
line: "{{ 'AuthenticationMethods publickey password' if sshd_password_auth else 'AuthenticationMethods publickey' }}"
}
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
validate: /usr/sbin/sshd -t -f %s
- name: "Check if there is an SSH config forced by cloud-init"
register: sshd_cloud_init
ansible.builtin.stat:
path: "/etc/ssh/sshd_config.d/50-cloud-init.conf"
- name: "Authentication | override password authentication by cloud-init to '{{ sshd_password_auth | ternary('yes', 'no') }}'"
when: sshd_cloud_init.stat.exists
notify: Restart sshd
ansible.builtin.lineinfile:
path: "/etc/ssh/sshd_config.d/50-cloud-init.conf"
regexp: '^#?PasswordAuthentication'
line: 'PasswordAuthentication {{ sshd_password_auth | ternary("yes", "no") }}'

View File

@@ -0,0 +1,11 @@
---
- name: "Encryption | remove unsafe host keys"
loop:
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ecdsa_key.pub
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_dsa_key.pub
notify: Restart sshd
ansible.builtin.file:
path: "{{ item }}"
state: absent

View File

@@ -0,0 +1,13 @@
---
- name: "Install | install OpenSSH (RHEL flavours)"
when: ansible_os_family == "RHEL"
ansible.builtin.dnf:
name: openssh
state: installed
- name: "Install | Install OpenSSH (Debian flavours)"
when: ansible_os_family == "Debian"
ansible.builtin.apt:
name: openssh-server
state: present
update_cache: true

23
roles/sshd/tasks/main.yml Normal file
View File

@@ -0,0 +1,23 @@
---
- name: "Install an OpenSSH server"
ansible.builtin.include_tasks: "install.yml"
- name: "Configure SSH algorithms"
ansible.builtin.include_tasks: "algorithms.yml"
- name: "Configure authentication methods"
ansible.builtin.include_tasks: "authentication.yml"
- name: "Configure SSH encryption keys"
ansible.builtin.include_tasks: "encryption.yml"
- name: "Configure additional restrictions"
ansible.builtin.include_tasks: "restrictions.yml"
- name: "Log at VERBOSE level"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?LogLevel'
line: 'LogLevel VERBOSE'
validate: sshd -f %s -t

View File

@@ -0,0 +1,30 @@
---
- name: "Restrictions | Configure SSH security restrictions"
loop:
- { regexp: '^#?Protocol\s+', line: 'Protocol 2' }
- { regexp: '^PermitRootLogin yes', line: 'PermitRootLogin no' }
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
- { regexp: '^#?IgnoreRhosts', line: 'IgnoreRhosts yes' }
- { regexp: '^#?DebianBanner\s+', line: 'DebianBanner no' }
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
validate: /usr/sbin/sshd -t -f %s
- name: "Restrictions | toggle PAM"
notify: Restart sshd
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?UsePAM'
line: "UsePAM {{ sshd_disable_pam | ternary('no', 'yes') }}"
validate: sshd -f %s -t
- name: "Restrictions | ensure the SSHD config is restricted to the root user"
notify: Restart sshd
ansible.builtin.file:
path: /etc/ssh/sshd_config
owner: root
group: root
mode: "0600"

1
roles/sshd/vars/main.yml Normal file
View File

@@ -0,0 +1 @@
---