base__ssh_listen_mesh_only binds sshd to the live wt0 IP only, with
ip_nonlocal_bind to beat the post-boot bind race and a fail-closed assert so an
unresolved address never silently listens on all interfaces. Molecule covers
the render + sysctl. Mesh-hardening 1/3 (ADR-016/021).
Environmental checkpoint applied: the molecule-debian13 container image lacks
procps (no sysctl binary). Added molecule/default/prepare.yml to install procps
and sysctls: {net.ipv4.ip_nonlocal_bind: "0"} to molecule.yml platform so the
ansible.posix.sysctl task can write and read back the value hermetically.
Sysctl file format is net.ipv4.ip_nonlocal_bind=1 (no spaces); verify.yml
grep pattern updated to match ansible.posix.sysctl's actual output.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
61 lines
1.9 KiB
YAML
61 lines
1.9 KiB
YAML
---
|
|
- name: Resolve the sshd mesh listen address (override, else live wt0 fact)
|
|
ansible.builtin.set_fact:
|
|
base__ssh_listen_addr_resolved: >-
|
|
{{ base__ssh_listen_addr
|
|
or ansible_facts.get('wt0', {}).get('ipv4', {}).get('address', '') }}
|
|
when: base__ssh_listen_mesh_only | bool
|
|
|
|
- name: Fail closed — refuse to render sshd without a known mesh address
|
|
ansible.builtin.assert:
|
|
that:
|
|
- base__ssh_listen_addr_resolved | length > 0
|
|
fail_msg: >-
|
|
base__ssh_listen_mesh_only is true but no mesh address resolved (set
|
|
base__ssh_listen_addr or ensure wt0 is up so its fact is gathered). Refusing to
|
|
render sshd ListenAddress empty (which would listen on ALL interfaces).
|
|
when: base__ssh_listen_mesh_only | bool
|
|
|
|
- name: Allow sshd to bind the mesh IP before wt0 exists at boot
|
|
ansible.posix.sysctl:
|
|
name: net.ipv4.ip_nonlocal_bind
|
|
value: "1"
|
|
sysctl_set: true
|
|
state: present
|
|
reload: true
|
|
sysctl_file: /etc/sysctl.d/60-boma-nonlocal-bind.conf
|
|
when: base__ssh_listen_mesh_only | bool
|
|
|
|
- name: Ensure openssh-server is installed
|
|
ansible.builtin.apt:
|
|
name: openssh-server
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Render hardened sshd drop-in
|
|
ansible.builtin.template:
|
|
src: sshd_hardening.conf.j2
|
|
dest: /etc/ssh/sshd_config.d/10-boma.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: reload sshd
|
|
|
|
- name: Ensure sshd privilege-separation directory exists (required for sshd -t)
|
|
ansible.builtin.file:
|
|
path: /run/sshd
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Validate the full sshd config (drop-in included)
|
|
ansible.builtin.command: sshd -t
|
|
changed_when: false
|
|
|
|
- name: Authorise control SSH keys for the ansible user
|
|
ansible.posix.authorized_key:
|
|
user: "{{ ansible_user | default('ansible') }}"
|
|
key: "{{ base__ssh_authorised_keys | join('\n') }}"
|
|
exclusive: true
|
|
when: base__ssh_authorised_keys | length > 0
|