base
The base role is the baseline every other role assumes. Apply it first.
What it does
Section titled “What it does”- Installs
base_packages(ca-certificates,curl,gnupg,htop,jq,rsync,unattended-upgrades). - Sets the time zone (
base_timezone, UTC by default). - Limits the systemd journal to
base_journald_max_use(500M). - Turns on unattended security upgrades, with an optional automatic reboot at a set time.
- Creates a swap file when
base_swap_size_mbis greater than 0, and setsvm.swappiness. - Hardens sshd with a drop-in (on by default, see below).
- Optionally adds static routes at boot, and lets services bind addresses that are not up yet.
SSH hardening
Section titled “SSH hardening”With base_sshd_hardening on (the default) the role writes /etc/ssh/sshd_config.d/50-base.conf and checks it with sshd -t before it is used. The drop-in:
- allows key-only login (
AuthenticationMethods publickey); - lets root log in with a key only (
base_sshd_permit_root_login); - disables agent and X11 forwarding, tunnels, gateway ports and user environment;
- turns TCP forwarding off (
base_sshd_allow_tcp_forwarding); - sets
MaxAuthTries 3,LoginGraceTime 30,MaxSessions 10(Ansible multiplexes sessions) andMaxStartups 10:30:60; - closes idle sessions after 10 minutes (
ClientAliveInterval 300,ClientAliveCountMax 2); - sets
LogLevel VERBOSE, so key fingerprints reach the log, which fail2ban and CrowdSec read; - allows only modern key exchange, cipher and MAC lists that OpenSSH 9.6 (Ubuntu 24.04) and later accept.
base_sshd_allow_users adds an AllowUsers line. Leave it empty and every user with a key may log in.
Key variables
Section titled “Key variables”| Variable | Default | Meaning |
|---|---|---|
base_sshd_hardening | true | Write the hardening drop-in. The other base_sshd_* options apply only while it is on. |
base_sshd_port | 22 | sshd port. fail2ban reads this value for its sshd jail. |
base_sshd_permit_root_login | prohibit-password | Set "no" once every play connects as an unprivileged user. |
base_sshd_allow_users | [] | AllowUsers patterns. Include the user Ansible connects as. |
base_sshd_listen_addresses | [] | Bind sshd to these addresses only. |
base_swap_size_mb | 0 | Swap file size in MiB; 0 leaves swap alone. |
base_unattended_reboot | false | Reboot when an upgrade needs it, at base_unattended_reboot_time. |
base_static_routes | [] | Routes as {to: CIDR, via: gateway}. |
All variables: base in the reference.
Example
Section titled “Example”- hosts: servers become: true roles: - role: noixdev.infra.base vars: base_timezone: Europe/Berlin base_swap_size_mb: 2048 base_sshd_allow_users: [deploy] base_sshd_permit_root_login: "no" base_unattended_reboot: true base_unattended_reboot_time: "04:00"Static routes behind a private gateway:
base_static_routes: - { to: 192.0.2.0/24, via: 198.51.100.1 }The role installs a oneshot unit that sets each route after the network is up, on the interface the gateway is reached through.
Gotchas
Section titled “Gotchas”- Include your Ansible user in
base_sshd_allow_users. With a non-empty list, a user who is not on it can no longer log in, and the next run cannot connect. - Hardening is key-only. A host that you reach by password stops accepting it as soon as the role runs. Install your key first.
base_sshd_listen_addresseschanges how sshd starts. When set, the role turns off socket activation (ssh.socket) and enablesnet.ipv4.ip_nonlocal_bindandnet.ipv6.ip_nonlocal_bind, so sshd starts before an address is up. Choose addresses you can still reach.- Keep
base_sshd_max_auth_triesabove the number of keys a client offers, or clients with many keys in their agent are refused before the right one is tried. MaxSessionsbelow 10 breaks Ansible’s connection multiplexing.- The default key exchange list works on OpenSSH 9.6 and later. Add
mlkem768x25519-sha256first only where every host runs OpenSSH 9.9 or later, because sshd refuses to start on an unknown algorithm name.