feat(security): add SSH hardening role
Port Modules/Security/secharden-ssh.sh. Deploys: - Authorized keys for root, localuser, subodev (conditional on existence) - Hardened /etc/ssh/sshd_config (skipped on dev workstations) - ssh-audit hardening drop-in for algorithm restrictions (skipped on Ubuntu where it breaks openssh-server) - Lockdown of sshd_config.d directory permissions SSH service is validated (sshd -t) before restart. 🤖 Generated with [Crush](https://github.com/charmassociates/crush) Assisted-by: GLM-5 via Crush <crush@charm.land>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHaBNuLS+GYGRPc9wne63Ocr+R+/Q01Y9V0FTv0RnG3
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyMR0lFgiMKhQJ5aqy68nR0BQp1cNzi/wIThyuTV4a8 tsyscto@ultix-control
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHaBNuLS+GYGRPc9wne63Ocr+R+/Q01Y9V0FTv0RnG3
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyMR0lFgiMKhQJ5aqy68nR0BQp1cNzi/wIThyuTV4a8 tsyscto@ultix-control
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com
|
||||||
|
# hardening guide.
|
||||||
|
KexAlgorithms sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256
|
||||||
|
|
||||||
|
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr
|
||||||
|
|
||||||
|
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com
|
||||||
|
|
||||||
|
HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
|
||||||
|
|
||||||
|
RequiredRSASize 3072
|
||||||
|
|
||||||
|
CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
|
||||||
|
|
||||||
|
GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-
|
||||||
|
|
||||||
|
HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256
|
||||||
|
|
||||||
|
PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Include /etc/ssh/sshd_config.d/*.conf
|
||||||
|
HostKey /etc/ssh/ssh_host_rsa_key
|
||||||
|
HostKey /etc/ssh/ssh_host_ed25519_key
|
||||||
|
KbdInteractiveAuthentication no
|
||||||
|
PrintMotd no
|
||||||
|
PasswordAuthentication no
|
||||||
|
AllowTcpForwarding no
|
||||||
|
X11Forwarding no
|
||||||
|
ChallengeResponseAuthentication no
|
||||||
|
AcceptEnv LANG LC_*
|
||||||
|
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||||
|
UsePAM yes
|
||||||
|
Banner /etc/issue.net
|
||||||
|
MaxAuthTries 2
|
||||||
|
MaxStartups 10:30:100
|
||||||
|
PermitRootLogin prohibit-password
|
||||||
|
ClientAliveInterval 300
|
||||||
|
ClientAliveCountMax 3
|
||||||
|
AllowUsers root localuser subodev
|
||||||
|
LoginGraceTime 60
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- name: Validate and restart sshd
|
||||||
|
ansible.builtin.command: sshd -t
|
||||||
|
changed_when: false
|
||||||
|
notify: Restart sshd
|
||||||
|
|
||||||
|
- name: Restart sshd
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: sshd
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
---
|
||||||
|
# SSH hardening — port of Modules/Security/secharden-ssh.sh.
|
||||||
|
|
||||||
|
# Per-user authorized_keys. The legacy script wrote localuser's keys into both
|
||||||
|
# localuser and subodev; replicate that mapping here. Deployed conditionally
|
||||||
|
# based on whether each user actually exists (legacy LOCALUSER_CHECK / SUBODEV_CHECK).
|
||||||
|
- name: Ensure root .ssh directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /root/.ssh
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
- name: Ensure localuser .ssh directory exists (if user exists)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /home/localuser/.ssh
|
||||||
|
state: directory
|
||||||
|
owner: localuser
|
||||||
|
group: localuser
|
||||||
|
mode: "0700"
|
||||||
|
when: localuser_exists | bool
|
||||||
|
|
||||||
|
- name: Ensure subodev .ssh directory exists (if user exists)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /home/subodev/.ssh
|
||||||
|
state: directory
|
||||||
|
owner: subodev
|
||||||
|
group: subodev
|
||||||
|
mode: "0700"
|
||||||
|
when: subodev_exists | bool
|
||||||
|
|
||||||
|
- name: Deploy root authorized_keys
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: authorized_keys/root
|
||||||
|
dest: /root/.ssh/authorized_keys
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0400"
|
||||||
|
|
||||||
|
- name: Deploy localuser authorized_keys (if user exists)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: authorized_keys/localuser
|
||||||
|
dest: /home/localuser/.ssh/authorized_keys
|
||||||
|
owner: localuser
|
||||||
|
group: localuser
|
||||||
|
mode: "0400"
|
||||||
|
when: localuser_exists | bool
|
||||||
|
|
||||||
|
- name: Deploy subodev authorized_keys (same keys as localuser, if user exists)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: authorized_keys/localuser
|
||||||
|
dest: /home/subodev/.ssh/authorized_keys
|
||||||
|
owner: subodev
|
||||||
|
group: subodev
|
||||||
|
mode: "0400"
|
||||||
|
when: subodev_exists | bool
|
||||||
|
|
||||||
|
# sshd_config — skipped on dev workstations (matches legacy DEV_WORKSTATION_CHECK).
|
||||||
|
# Uses the is_dev_workstation fact set by the preflight role based on the
|
||||||
|
# 'dev_workstations' inventory group.
|
||||||
|
- name: Deploy hardened /etc/ssh/sshd_config (non-dev hosts)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: configs/sshd_config
|
||||||
|
dest: /etc/ssh/sshd_config
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
backup: true
|
||||||
|
when: not (is_dev_workstation | bool)
|
||||||
|
notify: Validate and restart sshd
|
||||||
|
|
||||||
|
# ssh-audit hardening drop-in — breaks OpenSSH server on Ubuntu, so the legacy
|
||||||
|
# script skipped Ubuntu hosts. Replicate that guard.
|
||||||
|
- name: Deploy ssh-audit hardening drop-in (non-Ubuntu only)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: configs/ssh-audit-hardening.conf
|
||||||
|
dest: /etc/ssh/sshd_config.d/ssh-audit_hardening.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
backup: true
|
||||||
|
when: not (is_ubuntu | bool)
|
||||||
|
notify: Validate and restart sshd
|
||||||
|
|
||||||
|
- name: Lock down sshd_config.d drop-in permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/ssh/sshd_config.d
|
||||||
|
mode: "0700"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
Reference in New Issue
Block a user