Set SSH Client Alive Count Max

Classification:

compliance

Framework:

Control:

Description

The SSH server sends at most ClientAliveCountMax messages during a SSH session and waits for a response from the SSH client. The option ClientAliveInterval configures timeout after each ClientAliveCountMax message. If the SSH server does not receive a response from the client, then the connection is considered unresponsive and terminated. For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout functionality completely. If the option is set to a number greater than 0, then the session will be disconnected after ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message.

Rationale

This ensures a user login will be terminated as soon as the ClientAliveInterval is reached.

Remediation

Shell script

The following script can be run on the host to remediate the issue.

# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

var\_sshd\_set\_keepalive='3'


if [ -e "/etc/ssh/sshd\_config" ] ; then
 
 LC\_ALL=C sed -i "/^\s\*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd\_config"
else
 touch "/etc/ssh/sshd\_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd\_config"

cp "/etc/ssh/sshd\_config" "/etc/ssh/sshd\_config.bak"
# Insert before the line matching the regex '^Match'.
line\_number="$(LC\_ALL=C grep -n "^Match" "/etc/ssh/sshd\_config.bak" | LC\_ALL=C sed 's/:.\*//g')"
if [ -z "$line\_number" ]; then
 # There was no match of '^Match', insert at
 # the end of the file.
 printf '%s\n' "ClientAliveCountMax $var\_sshd\_set\_keepalive" >> "/etc/ssh/sshd\_config"
else
 head -n "$(( line\_number - 1 ))" "/etc/ssh/sshd\_config.bak" > "/etc/ssh/sshd\_config"
 printf '%s\n' "ClientAliveCountMax $var\_sshd\_set\_keepalive" >> "/etc/ssh/sshd\_config"
 tail -n "+$(( line\_number ))" "/etc/ssh/sshd\_config.bak" >> "/etc/ssh/sshd\_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd\_config.bak"

else
 >&2 echo 'Remediation is not applicable, nothing was done'
fi

Ansible playbook

The following playbook can be run with Ansible to remediate the issue.

- name: XCCDF Value var\_sshd\_set\_keepalive # promote to variable
 set\_fact:
 var\_sshd\_set\_keepalive: !!str 3
 tags:
 - always

- name: Set SSH Client Alive Count Max
 block:

 - name: Check for duplicate values
 lineinfile:
 path: /etc/ssh/sshd\_config
 create: false
 regexp: (?i)^\s\*ClientAliveCountMax\s+
 state: absent
 check\_mode: true
 changed\_when: false
 register: dupes

 - name: Deduplicate values from /etc/ssh/sshd\_config
 lineinfile:
 path: /etc/ssh/sshd\_config
 create: false
 regexp: (?i)^\s\*ClientAliveCountMax\s+
 state: absent
 when: dupes.found is defined and dupes.found > 1

 - name: Insert correct line to /etc/ssh/sshd\_config
 lineinfile:
 path: /etc/ssh/sshd\_config
 create: true
 regexp: (?i)^\s\*ClientAliveCountMax\s+
 line: ClientAliveCountMax {{ var\_sshd\_set\_keepalive }}
 state: present
 insertbefore: ^[#\s]\*Match
 validate: /usr/sbin/sshd -t -f %s
 when: ansible\_virtualization\_type not in ["docker", "lxc", "openvz", "podman", "container"]
 tags:
 - CJIS-5.5.6
 - DISA-STIG-UBTU-20-010036
 - NIST-800-171-3.1.11
 - NIST-800-53-AC-12
 - NIST-800-53-AC-17(a)
 - NIST-800-53-AC-2(5)
 - NIST-800-53-CM-6(a)
 - NIST-800-53-SC-10
 - PCI-DSS-Req-8.1.8
 - PCI-DSSv4-8.2.8
 - low\_complexity
 - low\_disruption
 - medium\_severity
 - no\_reboot\_needed
 - restrict\_strategy
 - sshd\_set\_keepalive