ServerGuard
MODULE 03 / SSH HARDENING

SSH Hardening

Review and manage SSH configuration.

  • Linux server
  • hardening

Module: SSH Hardening
Main file: ssh_hardening.py
Platform: Linux / Ubuntu
Language: Python 3
Technologies: Python, OpenSSH, systemd
Project: ServerGuard

Purpose of the module:

Automated hardening of SSH server security,
OpenSSH configuration verification, backup,
application of a controlled security policy
and safe restoration of the SSH configuration.

1. GENERAL DESCRIPTION

SSH Hardening is a server module of ServerGuard designed for automatic management of OpenSSH security settings.

The module allows you to:

  • check user privileges;
  • determine the SSH service;
  • check SSH status;
  • create the required directories;
  • create a backup of the configuration;
  • create the ServerGuard configuration;
  • verify the OpenSSH configuration;
  • apply the changes;
  • reload the SSH service;
  • verify the parameters actually applied;
  • determine the hardening state;
  • remove the ServerGuard configuration;
  • restore the previous configuration;
  • perform a rollback on error.

The main idea of the module:

ServerGuard does not modify the entire /etc/ssh/sshd_config.

Instead, a separate configuration fragment is used:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

The main file:

/etc/ssh/sshd_config

while remaining separate.

This approach allows ServerGuard to apply its own SSH policy without completely rewriting the administrator's existing configuration.

2. WHAT SSH HARDENING IS

Hardening is the strengthening of system security by restricting unnecessary or potentially dangerous capabilities.

In the context of SSH, this means changing the OpenSSH policy so that the server allows only the necessary features.

ServerGuard sets the following parameters:

PermitEmptyPasswords no

X11Forwarding no

AllowTcpForwarding no

AllowAgentForwarding no

MaxAuthTries 3

LoginGraceTime 30

Compression no

PermitRootLogin prohibit-password

This restricts:

  • empty passwords;
  • root password authentication;
  • the number of authentication attempts;
  • the authentication time;
  • X11 forwarding;
  • TCP forwarding;
  • SSH Agent Forwarding;
  • SSH compression.

3. SSH HARDENING IS NOT BRUTE-FORCE PROTECTION

It is important to separate the two tasks.

SSH Hardening is responsible for:

SSH POLICY

That is:

which capabilities are allowed;
which capabilities are prohibited;
which restrictions are applied.

The Security module is responsible for:

ATTACK DETECTION

For example:

  • analysis of failed logins;
  • detection of a large number of attempts;
  • IP analysis;
  • IP blocking;
  • brute-force protection.

Therefore:

SSH Hardening
    =
OpenSSH configuration hardening

and:

Security
    =
detection and blocking of suspicious activity.

These mechanisms complement each other.

4. MODULE ARCHITECTURE

General architecture:

ServerGuard
     |
     | SSH
     v
Linux Server
     |
     v
ssh_hardening.py
     |
     +------------------------+
     |                        |
     v                        v
OpenSSH configuration      systemd
     |                        |
     v                        v
sshd_config.d             SSH service
     |                        |
     +------------+-----------+
                  |
                  v
              OpenSSH
                  |
                  v
          Effective config
                  |
                  v
              Verification

The module interacts with:

1. the Linux file system;
2. OpenSSH;
3. systemd;
4. the SSH daemon;
5. the backup system.

5. MAIN PATHS

Main ServerGuard directory:

/opt/serverguard

Backup directory:

/opt/serverguard/backups

Main OpenSSH configuration:

/etc/ssh/sshd_config

ServerGuard configuration:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

Thus:

/etc/ssh/
    |
    +-- sshd_config
    |
    +-- sshd_config.d/
            |
            +-- 99-serverguard-hardening.conf

6. TECHNOLOGIES

The module is written in:

Python 3

Standard Python libraries are used:

sys
os
shutil
subprocess
datetime

No additional Python packages are required.

The following Linux system components are used for operation:

systemctl
sshd

Python acts as a control layer between ServerGuard and the operating system.

Simplified:

Python
   |
   +---- file system
   |
   +---- OpenSSH
   |
   +---- systemd
   |
   +---- backup
   |
   +---- configuration verification

7. PYTHON IMPORTS

The module uses:

import sys
import os
import shutil
import subprocess
from datetime import datetime

sys

Used for:

  • processing command-line arguments;
  • terminating the program;
  • returning the exit code.

For example:

python3 ssh_hardening.py apply

passes:

apply

through:

sys.argv

os

Used to work with the Linux file system.

In particular:

  • checking for root;
  • checking whether files exist;
  • creating directories;
  • deleting files;
  • setting permissions;
  • constructing paths.

shutil

Used for copying files.

Main function:

shutil.copy2()

Used for:

  • creating a backup;
  • restoring the configuration.

subprocess

Used to run system commands.

For example:

sshd -t

sshd -T

systemctl is-active ssh

systemctl reload ssh

datetime

Used to generate timestamps.

For example:

20260930_215300

As a result, a backup may be named:

sshd_config_20260930_215300.backup

8. PRIVILEGE REQUIREMENTS

Modifying:

/etc/ssh/

and managing the SSH service require elevated privileges.

Therefore, the module performs a root check.

The following is used:

os.geteuid() == 0

If the program is run without root:

ERROR: This script must be run as root.

The operation is terminated.

This is necessary for working with:

/etc/ssh/sshd_config

/etc/ssh/sshd_config.d/

/opt/serverguard/backups

and systemd.

9. EXECUTING LINUX COMMANDS

To run system commands, the following is used:

run_command(command, check=False)

Internally, it uses:

subprocess.run()

The function receives:

command

and returns:

returncode
stdout
stderr

Example:

code, stdout, stderr = run_command(
    ["sshd", "-t"]
)

If:

code == 0

the command completed successfully.

If the command failed, the following is used:

stderr

for diagnostics.

Thus, the Python module does not implement its own SSH daemon but manages the existing OpenSSH through standard Linux commands.

10. SSH SERVICE DISCOVERY

In Linux, the SSH service may be named:

ssh

or:

sshd

Therefore, the module must not depend rigidly on a single name.

The function:

get_ssh_service()

determines the service name in use.

After discovery, the result is used in subsequent operations.

For example:

systemctl is-active ssh

or:

systemctl is-active sshd

Similarly, the following is executed:

systemctl reload ssh

or:

systemctl reload sshd

11. SSH SERVICE CHECK

The function:

check_ssh_service()

checks:

  • whether the SSH service was found;
  • whether the SSH service is active.

The following is used:

systemctl is-active <service>

If the result is:

active

SSH is considered running.

Example:

SSH service: ACTIVE

If the service is inactive, its state is displayed to the user.

12. BACKUP

Modifying the SSH configuration is a potentially dangerous operation.

An error in the configuration can cause new SSH connections to be unable to establish.

Therefore, ServerGuard uses the principle:

BACKUP BEFORE CHANGE

Before changing the configuration, a backup is created.

The backup is located at:

/opt/serverguard/backups

13. BACKUP OF THE MAIN CONFIGURATION

The function:

backup_main_config()

works with:

/etc/ssh/sshd_config

A file is created:

sshd_config_YYYYMMDD_HHMMSS.backup

For example:

sshd_config_20260930_215300.backup

Copying uses:

shutil.copy2()

The timestamp allows multiple backups to be stored.

14. BACKUP OF THE SERVERGUARD CONFIGURATION

If the following already exists:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

it may also be saved before creating a new version.

Example:

99-serverguard-hardening_20260930_215300.backup

This way, the previous version of the ServerGuard policy can be preserved.

Important:

the main sshd_config

and:

ServerGuard hardening config

are backed up separately.

15. CREATING THE HARDENING CONFIGURATION

The function:

create_hardening_config()

creates:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

The ServerGuard policy is written to the file.

Main parameters:

PermitEmptyPasswords no

X11Forwarding no

AllowTcpForwarding no

AllowAgentForwarding no

MaxAuthTries 3

LoginGraceTime 30

Compression no

PermitRootLogin prohibit-password

After creation, the permissions are set:

0644

16. PermitEmptyPasswords

The parameter:

PermitEmptyPasswords no

prohibits the use of an empty password during SSH authentication.

The idea of the setting:

empty password
    |
    v
SSH authentication
    |
    v
prohibited

This eliminates the possibility of using an empty password as an SSH authentication mechanism.

17. X11Forwarding

ServerGuard sets:

X11Forwarding no

X11 Forwarding allows X11 graphics to be transmitted over SSH.

If the server is used primarily for:

  • server applications;
  • administration;
  • development;
  • background services;

X11 forwarding may not be needed.

Therefore, ServerGuard disables this capability.

Important:

SSH is NOT disabled by this.

Only X11 forwarding is disabled.

18. AllowTcpForwarding

ServerGuard sets:

AllowTcpForwarding no

TCP forwarding allows SSH to be used for network tunneling.

For example:

client
   |
   | SSH
   v
server
   |
   v
another network resource

If the server uses SSH tunnels, disabling TCP forwarding may change the existing workflow.

Therefore, this setting must be taken into account before applying hardening.

19. AllowAgentForwarding

ServerGuard sets:

AllowAgentForwarding no

SSH Agent Forwarding allows the SSH agent to be used over a remote connection.

This can be convenient when administering multiple servers.

If the server does not require this capability, ServerGuard disables it.

20. MaxAuthTries

ServerGuard sets:

MaxAuthTries 3

The parameter limits the number of authentication attempts within a single SSH connection.

Important:

MaxAuthTries 3

does not mean:

"the IP is blocked after three attempts".

These are different mechanisms.

IP blocking belongs to the separate Security system.

21. LoginGraceTime

ServerGuard sets:

LoginGraceTime 30

The client is given a limited time to complete authentication.

In the ServerGuard policy:

30 seconds

This reduces the lifetime of an unauthenticated connection.

22. Compression

ServerGuard sets:

Compression no

SSH compression is disabled.

This reduces the number of available SSH features if compression is not required by a particular server.

23. PermitRootLogin

ServerGuard sets:

PermitRootLogin prohibit-password

This means that root password authentication over SSH is prohibited.

At the same time, root key authentication may remain available if other OpenSSH settings allow it.

Thus:

root + password
    |
    v
prohibited

root + SSH key
    |
    v
may be allowed

This differs from:

PermitRootLogin no

With:

PermitRootLogin no

root is completely prohibited over SSH.

24. WHY prohibit-password IS USED

ServerGuard intentionally uses:

PermitRootLogin prohibit-password

rather than:

PermitRootLogin no

This preserves the possibility of administrative access via an SSH key.

The final login capability still depends on other OpenSSH parameters.

For example:

PubkeyAuthentication
PasswordAuthentication
AuthorizedKeysFile

and other settings.

Therefore, the final state is recommended to be verified via:

sshd -T

25. CONFIGURATION VERIFICATION

Before reload, ServerGuard uses:

sshd -t

The command checks the OpenSSH configuration for errors.

Conditionally:

sshd -t
   |
   +---- 0
   |      |
   |      v
   |   VALID
   |
   +---- != 0
          |
          v
       INVALID

If the configuration is invalid, the apply operation must not continue as successful.

26. WHY sshd -t IS IMPORTANT

Imagine:

ServerGuard
     |
     v
 creates config
     |
     v
   sshd -t
     |
   +---+
   |   |
  OK ERROR
   |   |
   v   v
 reload rollback

Thus, a syntax error is detected before the configuration is actually applied.

27. RELOAD SSH

After a successful check, the following is executed:

systemctl reload <ssh-service>

The following is used:

reload

rather than the mandatory:

restart

This allows the running SSH daemon to reread the configuration.

On a successful reload, the module continues with verification.

28. EFFECTIVE CONFIGURATION

After applying, the following is used:

sshd -T

The command shows the effective OpenSSH configuration.

This is especially important because OpenSSH may use multiple configuration files.

For example:

/etc/ssh/sshd_config

and:

/etc/ssh/sshd_config.d/*.conf

Therefore, the contents of a single file do not always equal the final SSH daemon configuration.

ServerGuard checks specifically the result of:

sshd -T

29. RETRIEVING VALUES

The function:

get_config_value(config, name)

retrieves the value of a parameter from the result of:

sshd -T

For example:

permitrootlogin prohibit-password

is parsed as:

name:
    permitrootlogin

value:
    prohibit-password

The comparison is performed case-insensitively.

If the parameter is missing:

unknown

30. VALUE COMPARISON

The function:

value_matches(actual, expected)

compares:

the actual value

and:

the expected value.

For:

prohibit-password

the following may also be taken into account:

without-password

This is due to differences in how this setting is represented across OpenSSH versions.

31. HARDENING CHECK

The main function:

check_hardening()

first checks:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

If the file does not exist:

ServerGuard hardening: NOT INSTALLED

If the file exists, the following is executed:

sshd -T

After that, the parameters are checked.

32. PARAMETERS CHECKED

The following are checked:

PermitRootLogin
PasswordAuthentication
PubkeyAuthentication
PermitEmptyPasswords
MaxAuthTries
LoginGraceTime
X11Forwarding
AllowTcpForwarding
AllowAgentForwarding
Compression

However, not all parameters are strict requirements.

33. REQUIRED PARAMETERS

The following parameters must match the ServerGuard policy:

PermitRootLogin
    prohibit-password

PermitEmptyPasswords
    no

MaxAuthTries
    3

LoginGraceTime
    30

X11Forwarding
    no

AllowTcpForwarding
    no

AllowAgentForwarding
    no

Compression
    no

If the value matches:

[OK]

If it differs:

[FAIL]

34. INFORMATIONAL PARAMETERS

For:

PasswordAuthentication

and:

PubkeyAuthentication

the module outputs the actual value as information.

That is, these parameters are shown to the user but are not used as a strict condition for successful hardening.

For example:

[INFO] PasswordAuthentication yes

does not necessarily mean an error.

35. CHECK RESULT

If all required parameters match the policy:

ServerGuard hardening: ENABLED

If at least one required parameter differs:

ServerGuard hardening: PARTIALLY APPLIED

This allows distinguishing between:

the file exists

and:

the policy is actually applied.

36. REMOVING HARDENING

The function:

remove_hardening_config()

removes:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

If the file does not exist, this is not considered a critical error.

Removal is used, in particular, during rollback.

37. THE COMPLETE APPLY PROCESS

The command:

ssh_hardening.py apply

starts the hardening application process.

The general sequence:

1. Root check
       |
       v
2. Creating directories
       |
       v
3. Backup sshd_config
       |
       v
4. Backup of the old ServerGuard config
       |
       v
5. Creating the new config
       |
       v
6. sshd -t
       |
       +---- ERROR ---> rollback
       |
       v
7. systemctl reload
       |
       +---- ERROR ---> rollback
       |
       v
8. sshd -T
       |
       v
9. Parameter check
       |
       v
10. Result

38. BACKUP BEFORE APPLY

Before modifying the main SSH configuration file, a backup is created.

If the backup could not be created:

APPLY

is cancelled.

The principle:

backup failed
     |
     v
hardening cancelled

This prevents changing the configuration without the ability to return to a saved version.

39. ROLLBACK ON sshd -t ERROR

If, after creating the ServerGuard configuration:

sshd -t

returns an error:

1. the error is output;
2. ServerGuard removes the created hardening config;
3. the operation is considered unsuccessful.

Diagram:

CREATE
  |
  v
sshd -t
  |
  v
ERROR
  |
  v
REMOVE CONFIG
  |
  v
CANCEL

40. ROLLBACK ON RELOAD ERROR

If:

sshd -t

is successful, but:

systemctl reload

ends with an error:

1. the error is output;
2. the hardening config is removed;
3. the operation is considered unsuccessful.

Diagram:

CONFIG
  |
  v
sshd -t
  |
  v
 OK
  |
  v
reload
  |
  v
ERROR
  |
  v
remove config

41. FINAL VERIFICATION

After a successful reload, ServerGuard executes:

check_hardening()

Internally, the following is used:

sshd -T

After that, the actual parameter values are checked.

Thus, the following sequence is used:

CREATE
   |
   v
VALIDATE
   |
   v
RELOAD
   |
   v
EFFECTIVE CONFIG
   |
   v
VERIFY

This is more important than merely checking whether the file exists.

42. APPLY RESULT

On complete success:

SSH HARDENING APPLIED SUCCESSFULLY

If the required parameters do not match the policy:

ServerGuard hardening was not fully applied.

Thus, the presence of the configuration file by itself is not considered sufficient proof of successful application.

43. VIEWING BACKUPS

The function:

list_backups()

shows the contents of:

/opt/serverguard/backups

Backup files are sorted so that newer versions are displayed before older ones.

For example:

1. sshd_config_20260930_215300.backup
2. sshd_config_20260930_204100.backup
3. sshd_config_20260929_190000.backup

The number is used when selecting a backup.

44. RESTORE

The module supports restoring the main SSH configuration.

The command:

ssh_hardening.py restore <backup_file>

uses the selected backup.

The main file being restored:

/etc/ssh/sshd_config

Important:

backup ServerGuard hardening config

is not the same as a backup of the main sshd_config.

The configurations are stored separately.

45. EMERGENCY COPY BEFORE RESTORE

Before restoration, the current:

/etc/ssh/sshd_config

is saved separately.

For example:

before_restore_20260930_215500.backup

This is an emergency backup.

It is needed to enable rollback if the selected old configuration turns out to be invalid.

46. RESTORE VERIFICATION

After copying the backup, the following is executed:

sshd -t

If the configuration is valid:

the process continues.

If the configuration is invalid:

ServerGuard attempts to restore the emergency backup.

Diagram:

RESTORE
   |
   v
sshd -t
   |
+--+--+
|     |

OK FAIL

|     |
v     v

RELOAD ROLLBACK

47. PROTECTION AGAINST PATH TRAVERSAL

The command:

ssh_hardening.py restore <backup_file>

accepts a backup name.

However, the user must not be able to pass an arbitrary file path.

Therefore, the backup name is validated.

Dangerous elements are prohibited:

/
\
..

For example, the following must be rejected:

../../etc/passwd

../backup

/tmp/file

..\file

Goal:

allow operation only within
/opt/serverguard/backups

This is protection against Path Traversal.

48. BACKUP TYPE VERIFICATION

Even if the file exists, its name is additionally checked.

Allowed types:

sshd_config_*.backup

and:

before_restore_*.backup

If the name does not match an allowed type:

Unsupported backup type.

Thus, a single existence check of the file is not sufficient.

49. THE CHECK COMMAND

The following is supported:

ssh_hardening.py check

The command performs an SSH check.

The following are checked:

  • the SSH service name;
  • the SSH state;
  • the presence of hardening;
  • effective configuration;
  • required parameters;
  • informational parameters.

Simplified:

CHECK
  |
  +-- SSH service
  |
  +-- Hardening file
  |
  +-- sshd -T
  |
  +-- Policy verification

50. THE APPLY COMMAND

The command:

ssh_hardening.py apply

starts the full application of the policy.

Main stages:

root check
    |
    v
backup
    |
    v
create config
    |
    v
sshd -t
    |
    v
reload SSH
    |
    v
sshd -T
    |
    v
verify

51. THE RESTORE COMMAND

The command:

ssh_hardening.py restore <backup_file>

performs:

  • root check;
  • backup name validation;
  • existence check;
  • backup type validation;
  • creation of an emergency backup;
  • restoration;
  • sshd -t;
  • rollback on error;
  • reload SSH.

52. PROGRAM COMMANDS

Main syntax:

ssh_hardening.py [check|apply|restore]

Check:

python3 ssh_hardening.py check

Apply:

python3 ssh_hardening.py apply

Restore:

python3 ssh_hardening.py restore sshd_config_20260930_215300.backup

An unknown command results in the message:

Unknown command

and the output of the correct syntax.

53. ENTRY POINT

At the end of the file, the standard Python construct is used:

if __name__ == "__main__":
    sys.exit(main())

This means: if the file is run directly:

python3 ssh_hardening.py

the following is called:

main()

The main() function analyzes:

sys.argv

and determines the required operation.

54. COMMAND HANDLING

The following are supported:

check
apply
restore

The logic:

check
   |
   v
command_check()

apply
   |
   v
command_apply()

restore
   |
   v
command_restore()

An unknown command fails with an error.

55. THE COMPLETE APPLY SCENARIO

The administrator runs:

python3 ssh_hardening.py apply

Step 1:

Root check.

Step 2:

Creating the required directories.

Step 3:

Backup:

/etc/ssh/sshd_config

Step 4:

Backup of the previous ServerGuard config,
if it exists.

Step 5:

Creating:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

Step 6:

Check:

sshd -t

Step 7:

Reload:

systemctl reload ssh

or:

systemctl reload sshd

Step 8:

Retrieving:

sshd -T

Step 9:

Policy check.

Step 10:

Generating the result.

56. SUCCESSFUL APPLY SCENARIO

Diagram:

root
  |
  v
backup
  |
  v
create config
  |
  v
sshd -t
  |
  v
VALID
  |
  v
reload
  |
  v
sshd -T
  |
  v
verify
  |
  v
SUCCESS

Result:

SSH HARDENING APPLIED SUCCESSFULLY

57. ERROR SCENARIO

If:

sshd -t

returns an error:

CREATE
  |
  v
sshd -t
  |
  v
ERROR
  |
  v
REMOVE HARDENING CONFIG
  |
  v
CANCEL

Thus, an incorrect ServerGuard fragment must not remain as a result of a failed application.

58. FAILED RELOAD SCENARIO

Scenario:

CREATE
  |
  v
sshd -t
  |
  v
SUCCESS
  |
  v
systemctl reload
  |
  v
ERROR
  |
  v
REMOVE HARDENING CONFIG
  |
  v
ERROR

The apply operation is considered unsuccessful.

59. RESTORE SCENARIO

The administrator selects:

sshd_config_20260930_210000.backup

ServerGuard performs:

1. Root check.
2. Name validation.
3. Existence check.
4. Allowed type check.
5. Creation of an emergency backup.
6. Copying the selected backup.
7. sshd -t.
8. Rollback on error.
9. Reload SSH.

Diagram:

SELECT BACKUP
     |
     v
VALIDATE INPUT
     |
     v
EMERGENCY BACKUP
     |
     v
RESTORE
     |
     v
sshd -t
     |
  +--+--+
  |     |
 OK    FAIL
  |     |
  v     v
RELOAD ROLLBACK
  |
  v
SUCCESS

60. MODULE SECURITY

The module implements several protective mechanisms.

1. ROOT CHECK

Only root can perform privileged operations.

2. BACKUP BEFORE CHANGE

A backup is created before any change.

3. CONFIG VALIDATION

The following is used:

sshd -t

4. EFFECTIVE CONFIG CHECK

The following is used:

sshd -T

5. EMERGENCY BACKUP

Before restore, the current configuration is saved.

6. ROLLBACK

If there is a problem with restoration, the emergency backup is used.

7. PATH TRAVERSAL PROTECTION

Dangerous path elements are prohibited.

8. BACKUP TYPE VALIDATION

Only the provided backup types are allowed.

61. WHAT EXACTLY SSH HARDENING PROTECTS

The module changes the OpenSSH policy.

It restricts:

  • empty passwords;
  • root password login;
  • the number of authentication attempts;
  • authentication time;
  • X11 forwarding;
  • TCP forwarding;
  • SSH Agent Forwarding;
  • SSH compression.

This is protection specifically at the level of:

SSH daemon configuration.

62. WHAT THE MODULE DOES NOT DO

SSH Hardening is NOT:

  • an antivirus;
  • a firewall;
  • IDS/IPS;
  • an IP blocking system;
  • a network packet analysis system;
  • a file monitoring system;
  • a malware detection system;
  • a full-fledged DDoS protection.

It is responsible for the OpenSSH configuration.

For example:

MaxAuthTries 3

does not mean:

"the IP will be blocked after three attempts".

A separate ServerGuard Security logic is used for IP detection and blocking.

63. SSH HARDENING AND SECURITY

The ServerGuard architecture separates responsibilities.

SSH Hardening:

OpenSSH configuration
      |
      +-- authentication limits
      +-- root login policy
      +-- forwarding
      +-- compression
      +-- empty passwords

Security:

SSH activity
      |
      +-- failed login detection
      +-- IP analysis
      +-- brute-force detection
      +-- blocking

One module does not replace the other.

64. SSH HARDENING AND FIREWALL

SSH Hardening is not a firewall.

It is not responsible for:

UFW rules
packet filtering
IP blocking

The levels can be represented as follows:

Internet
   |
   v
Firewall
   |
   v
SSH service
   |
   v
SSH authentication
   |
   v
SSH Hardening policy

Each level performs its own task.

65. FOR BEGINNERS

To explain the module as simply as possible:

SSH Hardening is a program that tells SSH:

"Use stricter security rules."

For example:

MaxAuthTries 3

means:

limit the number of authentication attempts
within a single SSH connection.

The parameter:

PermitEmptyPasswords no

means:

do not use empty passwords for SSH authentication.

The parameter:

X11Forwarding no

means:

disable X11 forwarding.

After the change, ServerGuard checks:

sshd -t

and then:

sshd -T

66. FOR EXPERIENCED DEVELOPERS

From a technical standpoint, ssh_hardening.py is a control layer over OpenSSH.

Main principles:

  • declarative security policy;
  • configuration fragment;
  • backup before mutation;
  • validation before reload;
  • effective configuration verification;
  • controlled rollback;
  • restricted restore input.

The main sequence:

BACKUP
   |
   v
GENERATE
   |
   v
VALIDATE
   |
   v
RELOAD
   |
   v
EFFECTIVE CONFIG
   |
   v
VERIFY

67. WHY A CONFIGURATION FRAGMENT IS USED

Instead of fully modifying:

/etc/ssh/sshd_config

ServerGuard creates:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

The advantage of this approach:

the main configuration file remains separate;

the ServerGuard policy has its own file;

updating ServerGuard does not require completely rewriting
the administrator's configuration;

rollback of the ServerGuard configuration can be performed separately.

68. WHY sshd -t IS USED

The command:

sshd -t

is a barrier before reload.

Conditionally:

sshd -t
   |
   +-- 0
   |    |
   |    v
   |  VALID
   |
   +-- != 0
        |
        v
      ERROR

Without this check, an incorrect configuration could be applied without the error being detected in advance.

69. WHY sshd -T IS USED

The command:

sshd -T

shows the resulting OpenSSH configuration.

This is especially important when the following are present:

/etc/ssh/sshd_config

and:

/etc/ssh/sshd_config.d/*.conf

ServerGuard checks not merely the created file but the resulting state that OpenSSH sees.

70. EFFECTIVE CONFIGURATION

Two concepts can be distinguished.

CONFIGURATION FILE:

99-serverguard-hardening.conf

and:

EFFECTIVE CONFIGURATION:

the result of sshd -T

The first shows:

what ServerGuard wrote.

The second shows:

what OpenSSH actually uses.

Therefore:

the file exists

does not necessarily mean:

the parameter is actually applied.

71. FUNCTION STRUCTURE

Main functions of the module:

run_command()
    launching Linux commands

check_root()
    root check

create_directories()
    creating directories

get_ssh_service()
    determining the SSH service

check_ssh_service()
    checking the SSH state

backup_main_config()
    backup sshd_config

backup_hardening_config()
    backup ServerGuard config

create_hardening_config()
    creating the hardening config

validate_ssh_config()
    running sshd -t

reload_ssh()
    reload SSH

get_effective_config()
    retrieving sshd -T

get_config_value()
    retrieving a parameter

value_matches()
    comparing the value

check_hardening()
    checking the policy

remove_hardening_config()
    removing the ServerGuard config

apply_hardening()
    full apply

list_backups()
    list of backups

restore_configuration()
    restore

command_check()
    the check command

command_apply()
    the apply command

command_restore()
    the restore command

main()
    program control point

72. HARDENING LIFECYCLE

The configuration goes through:

NOT INSTALLED
      |
      v
    APPLY
      |
      v
    BACKUP
      |
      v
    CREATE
      |
      v
   VALIDATE
      |
      v
    RELOAD
      |
      v
    VERIFY
      |
      v
    ENABLED

On error:

APPLY
  |
  v
ERROR
  |
  v
REMOVE / ROLLBACK
  |
  v
CANCEL

73. RESTORE LIFECYCLE

Restore:

SELECT BACKUP
      |
      v
VALIDATE INPUT
      |
      v
EMERGENCY BACKUP
      |
      v
RESTORE
      |
      v
VALIDATE
      |
   +--+--+
   |     |
  OK    FAIL
   |     |
   v     v
RELOAD  ROLLBACK
   |
   v
SUCCESS

74. IMPORTANT FEATURE OF RESTORE

Restoring the main configuration modifies:

/etc/ssh/sshd_config

But the ServerGuard hardening is located separately:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

Therefore:

restore sshd_config

does not automatically mean:

remove ServerGuard hardening.

After restoration, the resulting configuration should be verified via:

sshd -T

or:

python3 ssh_hardening.py check

75. PERMISSIONS OF THE HARDENING CONFIGURATION

After creation, the permissions are set:

0644

That is:

owner:
    read + write

group:
    read

others:
    read

The SSH daemon can read the configuration.

Modifying the file requires the appropriate privileges.

76. CONSOLE INTERFACE

The module uses ANSI colors:

RED
GREEN
YELLOW
CYAN
RESET

Purpose:

GREEN
    successful operation

RED
    error

YELLOW
    warning

CYAN
    informational message

This does not affect the operation of OpenSSH and is used only for the administrator's convenience when working with the console.

77. EXAMPLE OF A CONFIGURATION CHANGE

Before applying hardening:

PermitEmptyPasswords yes
MaxAuthTries 6
LoginGraceTime 120
X11Forwarding yes

ServerGuard applies:

PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no

Also:

AllowTcpForwarding no
AllowAgentForwarding no
Compression no
PermitRootLogin prohibit-password

After reload, the following is executed:

sshd -T

and the obtained values are checked.

78. EXAMPLE OF A SUCCESSFUL RESULT

As an example, the console may show:

[OK] SSH service: ACTIVE

[OK] PermitRootLogin: prohibit-password

[OK] PermitEmptyPasswords: no

[OK] MaxAuthTries: 3

[OK] LoginGraceTime: 30

[OK] X11Forwarding: no

[OK] AllowTcpForwarding: no

[OK] AllowAgentForwarding: no

[OK] Compression: no

After which:

ServerGuard hardening: ENABLED

79. EXAMPLE OF PARTIAL APPLICATION

If some parameters match the policy and some differ:

[OK] MaxAuthTries: 3
[OK] LoginGraceTime: 30
[FAIL] X11Forwarding: yes

then the result is:

ServerGuard hardening: PARTIALLY APPLIED

This means:

the ServerGuard configuration exists,

but:

the actual SSH configuration does not fully match
the ServerGuard policy.

80. WHY CHECKING AFTER RELOAD IS NECESSARY

Just:

systemctl reload

is not enough.

The correct logic:

create the configuration
      |
      v
check the syntax
      |
      v
reload
      |
      v
obtain the effective config
      |
      v
check the values

This makes it possible to detect situations where the configuration file exists but the resulting OpenSSH policy differs from the expected one.

81. IMPORTANT LIMITATIONS

Some hardening settings reduce SSH functionality.

For example:

AllowTcpForwarding no

may disable SSH tunnels.

AllowAgentForwarding no

may disrupt Agent Forwarding.

X11Forwarding no

disables X11 forwarding.

Compression no

disables SSH compression.

Therefore, applying hardening must take the purpose of the server into account.

82. IMPORTANT FOR ADMINISTRATORS

Before applying, it is recommended to make sure that a working administrative access exists.

It is especially important to check:

  • the administrator's SSH key;
  • the administrator user;
  • the ability to log in;
  • root policy;
  • forwarding requirements;
  • the presence of a backup or second access channel.

Despite the presence of backup and rollback, the administrator must understand which SSH capabilities are used by a particular server.

83. DIFFERENCE FROM MANUAL EDITING

The manual approach:

nano /etc/ssh/sshd_config

assumes that the administrator independently:

  • changes the settings;
  • saves a backup;
  • checks the syntax;
  • reload SSH;
  • checks the result;
  • performs a rollback if necessary.

ServerGuard combines these operations:

BACKUP
   |
   v
GENERATE
   |
   v
VALIDATE
   |
   v
RELOAD
   |
   v
VERIFY
   |
   v
RESULT

84. SERVERGUARD C++ AND PYTHON

In the ServerGuard architecture, the user interface may reside in a C++ application, while the Linux logic is performed by a Python module.

Simplified:

ServerGuard C++
      |
      | SSH
      v
Linux Server
      |
      v
ssh_hardening.py
      |
      +---- OpenSSH
      |
      +---- systemd
      |
      +---- filesystem

C++ may be responsible for:

  • GUI;
  • the SSH connection;
  • passing commands;
  • managing modules;
  • displaying results.

The Python module is directly responsible for the Linux operations of SSH Hardening.

85. COMPLETE DIAGRAM

                     SERVERGUARD
                           |
                           v
                    SSH CONNECTION
                           |
                           v
                     LINUX SERVER
                           |
                           v
                  ssh_hardening.py
                           |
           +---------------+---------------+
           |               |               |
           v               v               v
       Filesystem       systemctl         sshd
           |               |               |
           v               v               v
     /etc/ssh/         SSH service     OpenSSH
           |
           v
 99-serverguard-hardening.conf
           |
           v
       sshd -t
           |
           v
     SSH reload
           |
           v
       sshd -T
           |
           v
   Effective config
           |
           v
      Verification

86. COMMANDS FOR THE ADMINISTRATOR

Check SSH Hardening:

sudo python3 ssh_hardening.py check

Apply:

sudo python3 ssh_hardening.py apply

Restore a backup:

sudo python3 ssh_hardening.py restore <backup_file>

Check the OpenSSH syntax directly:

sudo sshd -t

View the effective configuration:

sudo sshd -T

Check a specific parameter:

sudo sshd -T | grep -i permitrootlogin

Check the SSH state:

sudo systemctl status ssh

or:

sudo systemctl status sshd

87. FILE CHECK

The main SSH file:

/etc/ssh/sshd_config

The ServerGuard file:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

Backup:

/opt/serverguard/backups/

To view the ServerGuard configuration:

sudo cat /etc/ssh/sshd_config.d/99-serverguard-hardening.conf

To view the backup:

sudo ls -lah /opt/serverguard/backups/

88. TYPICAL DIAGNOSTIC SEQUENCE

If hardening does not work as expected:

1. Check the SSH service.

2. Check the existence of:
   99-serverguard-hardening.conf

3. Run:

   sshd -t

4. Run:

   sshd -T

5. Check a specific parameter.

6. Run:

   python3 ssh_hardening.py check

7. View the backup if necessary.

89. WHAT TO CHECK WHEN PROBLEMS OCCUR

If SSH Hardening is not applied, the following must be checked:

  • whether the script is run as root;
  • whether /etc/ssh/ exists;
  • whether sshd exists;
  • whether the systemd service is found;
  • whether systemctl is available;
  • whether sshd_config exists;
  • whether the sshd_config.d directory is accessible;
  • whether sshd -t passes;
  • what result sshd -T gives;
  • whether the backup exists;
  • whether a setting that conflicts with the policy is in use.

90. THE PRINCIPLE OF BACKUP RECOVERY

The main principle:

NEVER MODIFY THE SSH CONFIGURATION
WITHOUT THE ABILITY TO REVERT.

Therefore:

APPLY
   |
   v
BACKUP
   |
   v
CHANGE

And for restore:

CURRENT CONFIG
   |
   v
EMERGENCY BACKUP
   |
   v
RESTORE
   |
   v
VALIDATE
   |
   +---- FAIL
   |
   v
ROLLBACK

91. KEY PRINCIPLE OF THE MODULE

SSH Hardening is built around the sequence:

BACKUP
   ↓
CONFIGURE
   ↓
VALIDATE
   ↓
RELOAD
   ↓
VERIFY
   ↓
SUCCESS

On a problem:

ERROR
   ↓
ROLLBACK

It is precisely this sequence that is the main architectural idea of the module.

92. SHORT DESCRIPTION FOR THE README

ServerGuard SSH Hardening is a Linux module for automated hardening of the OpenSSH configuration.

The module creates:

/etc/ssh/sshd_config.d/99-serverguard-hardening.conf

and applies the following restrictions:

  • prohibition of empty passwords;
  • prohibition of root password login;
  • MaxAuthTries = 3;
  • LoginGraceTime = 30;
  • disabling X11 Forwarding;
  • disabling TCP Forwarding;
  • disabling SSH Agent Forwarding;
  • disabling SSH Compression.

A backup is created before the change.

After creation, the configuration is verified via:

sshd -t

After reload, the effective configuration is verified via:

sshd -T

The module also supports:

  • backup;
  • restore;
  • emergency backup;
  • rollback;
  • verification of the effective configuration;
  • protection against Path Traversal.

93. CONCLUSION

ServerGuard SSH Hardening is a separate security layer of ServerGuard intended specifically for managing the OpenSSH policy.

The main task of the module:

not just to change the SSH configuration,

but to perform a controlled process:

1. check privileges;
2. determine the SSH service;
3. save the original configuration;
4. create the ServerGuard policy;
5. check the syntax;
6. apply the configuration;
7. check the actual values;
8. report the result;
9. perform restoration if necessary.

The main architectural diagram:

BACKUP
   ↓
CONFIGURE
   ↓
VALIDATE
   ↓
RELOAD
   ↓
VERIFY
   ↓
SUCCESS

On error:

ERROR
   ↓
ROLLBACK

Thus, SSH Hardening is not merely a set of OpenSSH parameters but an automated mechanism for managing, verifying, and restoring the SSH configuration of a Linux server.

Get started

Choose your platform

Download ServerGuard for your desktop.

WindowsDownload for Windows LinuxUbuntu, Fedora, Arch & more

Checking Windows download…