SSHD Ansible Role
An Ansible role to configure the OpenSSH server (sshd) on Debian-based systems.
Features
- Configure sshd settings (e.g., port, authentication, logging, session behavior)
- Install and manage
openssh-server
- Lightweight validation (checks sshd configuration syntax before applying)
- Support for per-user/group/address SSH configurations using Match blocks
Installation
Add the following to your requirements.yml:
roles:
- name: sshd
src: https://gitlab.com/niclas-zone/tools/ansible/roles/sshd.git
version: 1.13.0
scm: git
Then install:
ansible-galaxy install -r requirements.yml --force
Role Variables
General
| Variable |
Default |
Type |
Description |
ansible_managed_warning |
"This file is managed by Ansible. Manual changes will be overwritten." |
string |
Comment header written into every templated file to signal it is Ansible-managed. |
ansible_role_repository |
https://gitlab.com/niclas-zone/tools/ansible/roles/sshd |
string |
Source repository URL; embedded in the managed-file header so engineers know where to make changes. |
sshd_enabled |
true |
boolean |
Start and enable the sshd systemd service. Set to false to install the package but leave it off. |
sshd_validate_config |
true |
boolean |
Run sshd -t to validate the generated config before restarting the service. Disable only in test environments where the binary is unavailable. |
sshd_include_dir |
"/etc/ssh/sshd_config.d" |
string |
Drop-in directory included at the end of sshd_config. Files here are loaded in lexicographic order. |
Network & Binding
| Variable |
Default |
Type |
Description |
sshd_port |
22 |
integer |
TCP port sshd listens on. |
sshd_address_family |
"any" |
string |
Restrict the socket address family. any binds on both IPv4 and IPv6; inet for IPv4-only; inet6 for IPv6-only. Set to null to omit the directive entirely. |
sshd_listen_addresses |
[] |
list[str] |
Explicit IP addresses to bind. Empty list keeps the default (bind all interfaces). |
sshd_host_keys |
["/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_ecdsa_key", "/etc/ssh/ssh_host_ed25519_key"] |
list[str] |
Private host key files loaded on startup. Empty list falls back to OpenSSH's compiled-in defaults (commented out). |
sshd_use_dns |
false |
boolean |
Resolve client IPs to hostnames during authentication. Disabled by default to avoid slow logins when DNS is unreachable. |
Logging
| Variable |
Default |
Type |
Description |
sshd_syslog_facility |
"AUTH" |
string |
Syslog facility used for log messages. AUTH routes SSH logs to the standard authentication log (/var/log/auth.log on Debian). |
sshd_log_level |
"VERBOSE" |
string |
Log verbosity. VERBOSE additionally logs the fingerprint of the public key used in each successful authentication — useful for auditing. |
Authentication
| Variable |
Default |
Type |
Description |
sshd_login_grace_time |
"60" |
string |
Seconds the server waits for a client to complete authentication after connecting. The connection is dropped after this period regardless of authentication state. |
sshd_permit_root_login |
"no" |
string |
Controls root login. no blocks all root logins; prohibit-password allows key-based only; yes allows everything (strongly discouraged). |
sshd_strict_modes |
true |
boolean |
Reject logins if the user's ~/.ssh directory or authorized keys file has wrong ownership or permissions (e.g., world-writable). Prevents trivially compromised key files. |
sshd_max_auth_tries |
2 |
integer |
Maximum authentication attempts per connection before the server closes it. Limits brute-force exposure per TCP session. |
sshd_max_sessions |
10 |
integer |
Maximum simultaneous multiplexed sessions per connection (SSH multiplexing / ControlMaster). |
sshd_password_authentication |
true |
boolean |
Allow password-based authentication. Set to false when all users authenticate via public keys. |
sshd_pubkey_authentication |
true |
boolean |
Allow public key authentication. This is the recommended primary method. |
sshd_kbd_interactive_authentication |
false |
boolean |
Allow keyboard-interactive authentication (e.g., PAM challenge-response). Disabled by default; enabling it alongside PAM can enable 2FA prompts. |
sshd_permit_empty_passwords |
false |
boolean |
Allow logins to accounts with no password set. Never enable this on any system reachable from a network. |
sshd_authorized_keys_file |
[".ssh/authorized_keys"] |
list[str] |
Files containing public keys for key-based authentication, relative to the user's home directory. |
sshd_authorized_principals_file |
"none" |
string |
File listing allowed certificate principals per user. none disables certificate-principal matching. |
sshd_authorized_keys_command |
"none" |
string |
External command to fetch authorized keys (e.g., from LDAP). none disables the feature. |
sshd_authorized_keys_command_user |
"nobody" |
string |
Unprivileged user under which AuthorizedKeysCommand runs. |
sshd_hostbased_authentication |
false |
boolean |
Allow host-based authentication (trust relationships between hosts). Disabled by default; rarely appropriate on modern systems. |
sshd_ignore_user_known_hosts |
false |
boolean |
Ignore ~/.ssh/known_hosts during host-based authentication. |
sshd_ignore_rhosts |
true |
boolean |
Ignore ~/.rhosts and ~/.shosts. Always keep true; .rhosts authentication is insecure and obsolete. |
User Access Control
| Variable |
Default |
Type |
Description |
sshd_allow_users |
[] |
list[str] |
Explicit list of users permitted to log in. When non-empty, all other users are implicitly denied. Supports wildcards and @group notation. Empty = allow all. |
sshd_deny_users |
[] |
list[str] |
Users explicitly denied SSH access. Applied before AllowUsers. Supports wildcards. |
sshd_allow_groups |
[] |
list[str] |
Groups whose members are permitted to log in. When non-empty, users not in any listed group are denied. Empty = allow all. |
sshd_deny_groups |
[] |
list[str] |
Groups whose members are denied SSH access. |
Kerberos & GSSAPI
| Variable |
Default |
Type |
Description |
sshd_kerberos_authentication |
false |
boolean |
Authenticate against a Kerberos KDC instead of (or in addition to) local passwords. |
sshd_kerberos_or_local_passwd |
true |
boolean |
Fall back to local password check if Kerberos authentication fails. |
sshd_kerberos_ticket_cleanup |
true |
boolean |
Destroy the user's Kerberos ticket cache on logout. |
sshd_kerberos_get_afs_token |
false |
boolean |
Obtain an AFS token after Kerberos authentication. Only rendered when true; removed in OpenSSH 9.0+. |
sshd_gssapi_authentication |
false |
boolean |
Enable GSSAPI (Kerberos SSO) authentication. |
sshd_gssapi_cleanup_credentials |
true |
boolean |
Destroy GSSAPI credentials on logout. |
sshd_gssapi_strict_acceptor_check |
true |
boolean |
Enforce strict matching of the GSSAPI acceptor name to the server's hostname. |
sshd_gssapi_key_exchange |
false |
boolean |
Allow GSSAPI-based key exchange (authenticates both host and user via Kerberos). |
PAM
| Variable |
Default |
Type |
Description |
sshd_use_pam |
true |
boolean |
Enable PAM for account processing and session setup (e.g., pam_limits, pam_motd, pam_unix). Required when using PAM-based 2FA or account restrictions. |
Forwarding
| Variable |
Default |
Type |
Description |
sshd_disable_forwarding |
true |
boolean |
Single directive that disables all forwarding (X11, agent, TCP, StreamLocal) at once. When true, overrides the individual forwarding variables below. |
sshd_allow_agent_forwarding |
false |
boolean |
Allow SSH agent forwarding (ssh -A). Unnecessary on most servers and can be abused if the server is compromised; keep false unless specifically needed. |
sshd_allow_tcp_forwarding |
false |
boolean |
Allow TCP port forwarding / tunneling (ssh -L/-R). Disabled by default to prevent the SSH daemon from being used as a proxy or pivot. |
sshd_gateway_ports |
false |
boolean |
Allow remote port forwards to bind on non-loopback interfaces (i.e., accept connections from other hosts). Keep false to restrict forwarded ports to localhost only. |
sshd_permit_tunnel |
false |
boolean |
Allow tun/tap device tunneling (ssh -w). Disabled because it grants network-layer access. |
X11
| Variable |
Default |
Type |
Description |
sshd_x11_forwarding |
false |
boolean |
Enable X11 display forwarding. Disabled by default; X11 forwarding gives the remote server access to the local display. |
sshd_x11_display_offset |
10 |
integer |
Offset added to the X11 display number allocated for forwarding sessions (:10, :11, …). Avoids conflicts with local displays. |
sshd_x11_use_localhost |
true |
boolean |
Bind the forwarded X11 socket to localhost only. Prevents other hosts from connecting to the forwarded display. |
Session Behavior
| Variable |
Default |
Type |
Description |
sshd_permit_tty |
true |
boolean |
Allow the allocation of a pseudo-terminal (PTY). Set to false for SFTP-only accounts where interactive shells are unwanted. |
sshd_print_motd |
false |
boolean |
Print /etc/motd on login. Disabled here because PAM (pam_motd) typically handles this; enabling both causes duplicate output. |
sshd_print_last_log |
true |
boolean |
Show the date/time and source IP of the user's last login on each login. Helps users detect unexpected access. |
sshd_permit_user_environment |
false |
boolean |
Allow users to set environment variables via ~/.ssh/environment. Disabled because it can be used to bypass ForceCommand or PATH restrictions. |
sshd_accept_env |
see below |
list[str] |
Environment variables the client is allowed to pass through to the session. Restricted to locale and color variables by default. |
sshd_chroot_directory |
"none" |
string |
chroot(2) the session into this directory after authentication. none disables chrooting. Useful for restricting SFTP users to a specific directory tree. |
sshd_compression |
"delayed" |
string |
SSH compression. delayed activates compression only after authentication, preventing CPU exhaustion from unauthenticated compressed data. yes compresses from the start; no disables compression. |
sshd_rekey_limit |
"default none" |
string |
Force renegotiation of session keys after a data volume (default = 1 GB) or time (none = no time limit). default none uses OpenSSH's built-in thresholds. |
sshd_version_addendum |
"none" |
string |
Text appended to the SSH protocol banner (e.g., SSH-2.0-OpenSSH_9.2 <addendum>). none suppresses the addendum, reducing version disclosure to unauthenticated scanners. |
sshd_banner |
"/etc/issue.net" |
string |
Path to a file whose contents are displayed to the client before authentication. Typically contains a legal warning. |
Session Keepalive
| Variable |
Default |
Type |
Description |
sshd_tcp_keep_alive |
true |
boolean |
Enable OS-level TCP keepalives (SO_KEEPALIVE). The kernel sends TCP probes independently of SSH. Helps detect truly dead TCP connections and keeps NAT/firewall table entries alive. These probes are spoofable at the network layer. |
sshd_client_alive_interval |
60 |
integer |
Seconds between encrypted keepalive probes sent from the server to the client through the SSH channel. 0 disables SSH-level keepalives entirely. These probes are encrypted and cannot be spoofed. |
sshd_client_alive_count_max |
0 |
integer |
How many consecutive unanswered keepalives before the server terminates the session. 0 (default) disables auto-disconnect — keepalives are still sent (maintaining NAT entries) but the session is never dropped. Set to a positive integer to re-enable disconnect (e.g., 3 = disconnect after 3 × 60 s = 3 min of silence). |
Connection Throttling & Limits
| Variable |
Default |
Type |
Description |
sshd_max_startups |
"10:30:60" |
string |
Throttle unauthenticated connections using start:rate:full format. At 10 unauthenticated connections, begin randomly dropping new ones at 30% probability; hard-reject all above 60. Protects against connection floods. |
sshd_pid_file |
"/run/sshd.pid" |
string |
Path to the PID file written by the sshd master process. Used by init scripts and systemd to manage the service. |
Subsystems & Other
| Variable |
Default |
Type |
Description |
sshd_subsystem_sftp |
"/usr/lib/openssh/sftp-server" |
string |
Path to the SFTP server binary. This enables the sftp subsystem (sftp user@host). |
sshd_match_blocks |
[] |
list[dict] |
Per-user/group/address override blocks. Each entry becomes a Match stanza in sshd_config. See below for structure. |
Cryptographic Algorithms
| Variable |
Default |
Type |
Description |
sshd_kex_algorithms |
see below |
list[str] |
Allowed key exchange algorithms, ordered by preference. Restricts to modern ECDH and DH-group-exchange methods; removes weaker SHA-1 based algorithms. |
sshd_ciphers |
see below |
list[str] |
Symmetric ciphers allowed for bulk encryption, ordered by preference. Prefers AEAD modes (ChaCha20, AES-GCM) over CTR modes. |
sshd_macs |
see below |
list[str] |
Message authentication codes for integrity protection, ordered by preference. Prefers ETM (Encrypt-then-MAC) variants. |
Session Keepalive Behavior
Two complementary mechanisms prevent idle session disconnections:
OS-level TCP keepalives (TCPKeepAlive yes): The kernel sends TCP-layer probes at intervals controlled by the OS (net.ipv4.tcp_keepalive_*). These operate below the SSH layer — spoofable but effective at keeping NAT/firewall table entries alive and at detecting broken TCP stacks.
SSH-level encrypted keepalives (ClientAliveInterval 60 + ClientAliveCountMax 0): The SSH daemon sends a null packet through the encrypted channel every 60 seconds. Because ClientAliveCountMax is 0, the server never disconnects the client regardless of how many keepalives go unanswered. This prevents accidental dropouts on flaky networks (Wi-Fi, VPN, high-latency links).
To enable automatic cleanup of truly dead sessions, set sshd_client_alive_count_max to a positive integer:
sshd_client_alive_interval: 60
sshd_client_alive_count_max: 3 # disconnect after 3 × 60 s = 3 min of silence
Default Cryptographic Algorithms
The role includes hardened defaults for cryptographic algorithms:
sshd_kex_algorithms:
- "curve25519-sha256@libssh.org"
- "ecdh-sha2-nistp521"
- "ecdh-sha2-nistp384"
- "ecdh-sha2-nistp256"
- "diffie-hellman-group-exchange-sha256"
sshd_ciphers:
- "chacha20-poly1305@openssh.com"
- "aes256-gcm@openssh.com"
- "aes128-gcm@openssh.com"
- "aes256-ctr"
- "aes192-ctr"
- "aes128-ctr"
sshd_macs:
- "hmac-sha2-512-etm@openssh.com"
- "hmac-sha2-256-etm@openssh.com"
- "hmac-sha2-512"
- "hmac-sha2-256"
Default Environment Variables
sshd_accept_env:
- "LANG"
- "LC_*"
- "COLORTERM"
- "NO_COLOR"
Per-User/Group/Address Configurations
The sshd_match_blocks variable allows you to define SSH configurations that apply only to specific users, groups, or addresses. Each block is a dictionary with:
name: (required) A descriptive comment for the Match block
match: (required) The Match criteria (e.g., User, Group, Address, or combinations)
settings: (required) A dictionary of SSH settings to apply for this Match block
Example Playbooks
---
- hosts: servers
become: true
roles:
- role: sshd
Custom sshd settings
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
sshd_port: 2222
sshd_permit_root_login: "prohibit-password"
sshd_password_authentication: false
sshd_pubkey_authentication: true
sshd_max_auth_tries: 3
sshd_max_sessions: 5
sshd_x11_forwarding: false
Minimal configuration (disable password authentication)
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
sshd_password_authentication: false
sshd_pubkey_authentication: true
Per-user SSH configurations
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
# Global settings
sshd_permit_root_login: "no"
sshd_password_authentication: false
# Per-user/group/address overrides using Match blocks
sshd_match_blocks:
# Restrict root login from a specific IP
- name: "Restrict root login from admin host"
match: "Address 10.0.2.31"
settings:
PermitRootLogin: "yes"
# Allow password authentication for specific user from subnet
- name: "Allow password auth for admin user"
match: "User admin Address 10.0.2.*"
settings:
PasswordAuthentication: "yes"
# Allow password authentication only for specific group
- name: "Allow password for system administrators group"
match: "Group sysadmin"
settings:
PasswordAuthentication: "yes"
# Restrict port forwarding for specific users
- name: "Disable forwarding for guest users"
match: "User guest"
settings:
AllowTcpForwarding: "no"
AllowAgentForwarding: "no"
Advanced: Combining Match blocks with different conditions
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
sshd_match_blocks:
# subnet role
- name: "Allow root from internal subnet with key-only auth"
match: "User root Address 192.168.0.*"
settings:
PermitRootLogin: "prohibit-password"
PasswordAuthentication: "no"
# Group Specific role
- name: "Service account configuration"
match: "Group service-accounts"
settings:
AllowTcpForwarding: "yes"
X11Forwarding: "no"
PermitTTY: "no"
ForceCommand: "internal-sftp"
User Access Control: Allow and Deny specific users
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
# Method 1: Allow only specific users
sshd_allow_users:
- vivek
- jerry
- admin
# Method 2: Deny specific users (allow all others)
# sshd_deny_users:
# - root
# - saroj
# - guest
User Access Control: Restrict SSH with patterns
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
# Allow users and patterns (wildcards supported)
sshd_allow_users:
- admin
- "user*" # Allow user1, user2, user3, etc.
- "@admins" # Allow users in the 'admins' group
# Deny specific users and patterns
sshd_deny_users:
- root
- "test*" # Deny test1, test2, test3, etc.
- "guest*"
Cryptographic hardening with custom algorithms
---
- hosts: servers
become: true
roles:
- role: sshd
vars:
# Use stricter cryptographic algorithms
sshd_kex_algorithms:
- "curve25519-sha256@libssh.org"
- "curve25519-sha256"
sshd_ciphers:
- "chacha20-poly1305@openssh.com"
- "aes256-gcm@openssh.com"
sshd_macs:
- "hmac-sha2-512-etm@openssh.com"
- "hmac-sha2-256-etm@openssh.com"