diff --git a/CLAUDE.md b/CLAUDE.md index bcc0ec1..1eff89f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -74,7 +74,7 @@ subdomain. ### Roles (`site.yml` runs common, docker, cron) - **bootstrap**: user, SSH key, passwordless sudo, UFW, then `artis3n.tailscale`. -- **common**: `aptitude`, `jq`, daily unattended security updates, UFW on with default deny. +- **common**: `aptitude`, `jq`, daily unattended security updates, SSH keys only (no root login), UFW on with default deny. - **docker**: Docker CE, shell setup (zsh, Atuin, bat), ufw-docker, the `lava` network, and every service. - **cron**: dockcheck (08:00, auto-updates labelled containers, Gotify notices) diff --git a/roles/common/README.md b/roles/common/README.md index 5c5b75a..5225d6e 100644 --- a/roles/common/README.md +++ b/roles/common/README.md @@ -6,6 +6,8 @@ Base setup applied first by `site.yml` (tag `common`). - Installs `aptitude` and `jq`. - Installs `unattended-upgrades` and turns on daily security updates (Debian security archive only, no automatic reboots). +- SSH: keys only, no root login, no X11 forwarding + (`/etc/ssh/sshd_config.d/10-hardening.conf`, reloads ssh when changed). - Makes sure UFW is enabled with default deny. The SSH rule comes from the bootstrap role, and container rules from `ufw-docker` in the docker role. diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml new file mode 100644 index 0000000..1b36bec --- /dev/null +++ b/roles/common/handlers/main.yml @@ -0,0 +1,4 @@ +- name: reload ssh + ansible.builtin.systemd: + name: ssh + state: reloaded diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 257e0ac..c9fc7fa 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -25,3 +25,19 @@ content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; + +# Keys only. sshd_config's Include comes first and sshd keeps the first value +# it reads, so this drop-in overrides the defaults further down. Root has no +# keys, and Ansible logs in as the regular user. +- name: SSH - keys only, no root login, no X11 + ansible.builtin.copy: + dest: /etc/ssh/sshd_config.d/10-hardening.conf + owner: root + mode: '0644' + content: | + PasswordAuthentication no + KbdInteractiveAuthentication no + PermitRootLogin no + X11Forwarding no + validate: /usr/sbin/sshd -t -f %s + notify: reload ssh