legacy-of-lunatic-kingdom: make the restic account sftp-only
sftp previously worked through useradd's empty-shell default, and the keys could open a shell.
Assisted-by: GLM-5.3 via pi
diff --git a/docs/legacy-of-lunatic-kingdom.md b/docs/legacy-of-lunatic-kingdom.md
index e88b262..b04fe99 100644
--- a/docs/legacy-of-lunatic-kingdom.md
+++ b/docs/legacy-of-lunatic-kingdom.md
@@ -55,7 +55,7 @@ can scrape caddy's metrics endpoint.
|---|---|---|
| caddy | Quadlet container | [caddy.yml][caddy] |
| syncthing | Debian package, `syncthing@syncthing.service` | [syncthing.yml][syncthing] |
-| restic repository | sftp directory under the `restic` user | [main.yml][main] |
+| restic repository | sftp-only `restic` user | [main.yml][main] |
| node-exporter | Debian package, with apt and systemd collectors | [main.yml][main] |
| journal-upload | ships journald to VictoriaLogs on lotus-land-story | [journal-upload.yml][journal] |
| unattended-upgrades | Debian package, weekly apply with security-only origins | [unattended-upgrades.yml][upgrades] |
diff --git a/legacy-of-lunatic-kingdom/main.yml b/legacy-of-lunatic-kingdom/main.yml
index b2587c2..e46d513 100644
--- a/legacy-of-lunatic-kingdom/main.yml
+++ b/legacy-of-lunatic-kingdom/main.yml
@@ -109,6 +109,21 @@
become: true
tasks:
+ # Applied before the account changes below so sftp never briefly depends
+ # on the user's shell; internal-sftp serves absolute paths, so the
+ # repository URL stays as it is.
+ - name: Restrict the restic user to sftp
+ ansible.builtin.blockinfile:
+ path: /etc/ssh/sshd_config
+ block: |
+ Match User restic
+ ForceCommand internal-sftp
+ AllowTcpForwarding no
+ X11Forwarding no
+ validate: /usr/sbin/sshd -t -f %s
+ mode: "0644"
+ notify: Restart sshd
+
- name: Create Restic user
ansible.builtin.user:
name: restic
@@ -117,12 +132,17 @@
# which is how Debian creates system users. '*' is not locked but
# can never match a password.
password: "*"
+ # internal-sftp needs no shell.
+ shell: /usr/sbin/nologin
state: present
- name: Add SSH key for restic user
ansible.posix.authorized_key:
user: restic
key: "{{ item }}"
+ # ForceCommand confines; restrict also kills forwarding and pty at
+ # the auth layer.
+ key_options: restrict
loop:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrlVay1GlpCuhYSUup/K/gRYmltycViPBAdZ8t9OKtu # lotus-land-story
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPgX0tA28NO3djYaV++JxggR0t47xou+R0HQVwVjzj8s # 1password
@@ -135,6 +155,12 @@
group: restic
mode: "0755"
+ handlers:
+ - name: Restart sshd
+ ansible.builtin.systemd:
+ name: sshd
+ state: restarted
+
- name: Keep dhcpcd out of resolv.conf
# Trixie's ifupdown uses dhcpcd for the dhcp method, and it rewrites
# /etc/resolv.conf on every lease event, stomping the file tailscaled owns