During a recent audit of a multi-cloud environment spanning AWS Mumbai (ap-south-1) and a local Indian provider, E2E Networks, I discovered that 70% of the bastion hosts were vulnerable to the Terrapin attack (CVE-2023-48795). Most of these instances were running default configurations provided by the cloud vendor's base OS images. These defaults often prioritize compatibility over security, leaving administrative interfaces exposed to sophisticated downgrade attacks and brute-force attempts.
The Reality of Modern SSH Vulnerabilities
The discovery of CVE-2024-6387, also known as RegreSSHion, has fundamentally changed how we view SSH security. This vulnerability is a race condition in OpenSSH's server (sshd) that allows unauthenticated remote code execution (RCE) as root on glibc-based Linux systems. In an environment where bastions serve as the primary entry point for managing production databases and microservices, an unpatched SSH daemon is a catastrophic failure point.
Defining Security Hardening in the Bastion Context
Security hardening is the process of reducing the attack surface of a system by removing unnecessary software, services, and insecure default settings. For an SSH bastion, this means hardening Linux infrastructure to transform the service from a general-purpose remote access tool into a strictly controlled, single-purpose gateway. We are not just changing a port; we are re-engineering the authentication and encryption pipeline.
Why SSH Integrity Governs Server Security
The bastion host is the "crown jewel" of your infrastructure's perimeter. If an attacker gains root access to the bastion, they bypass network-level isolation (VPCs) and can pivot internally using captured credentials or active SSH sessions. In the Indian regulatory landscape, specifically under the DPDP Act 2023, a breach of this nature could be classified as a failure to implement "reasonable security safeguards," leading to significant financial penalties.
Moving Beyond Password Authentication
Passwords are the weakest link in any SSH implementation. They are susceptible to brute-force attacks, credential stuffing, and social engineering. I recommend a strict "Keys Only" policy or adopting secure SSH access for teams to eliminate credential risks. We start by generating high-entropy keys using the Ed25519 algorithm, which offers better security and performance compared to RSA.
# Generate a hardened Ed25519 key with 100 KDF rounds for increased brute-force resistance
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_bastion_prod -C "admin-access-key"
The -a 100 flag increases the number of Key Derivation Function (KDF) rounds, making the private key file significantly harder to crack if it is ever exfiltrated.
Disabling Root Login and Password Auth
Administrative exploits often target the root user directly. By disabling root login, we force attackers to first guess a valid non-privileged username and then attempt a privilege escalation. This adds a critical layer of friction.
# Edit /etc/ssh/sshd_config or create a drop-in file
Ensure these parameters are set:
PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no
Enforcing Strong Cryptographic Algorithms
Many legacy SSH clients and servers still support SHA-1 or MD5-based MACs and weak ciphers like 3DES. To mitigate the Terrapin attack and other cryptographic weaknesses documented by the NIST NVD, we must explicitly define the allowed ciphers, Key Exchange (Kex) algorithms, and Message Authentication Codes (MACs).
# Restrict to modern, secure primitives in /etc/ssh/sshd_config.d/hardened.conf
Ciphers [email protected],[email protected] KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256 MACs [email protected],[email protected]
The use of "Encrypt-then-MAC" (EtM) variants is vital. These protect against certain types of side-channel attacks by calculating the MAC after the data is encrypted.
Practical Configuration Hardening
Changing the default SSH port (22) is often dismissed as "security by obscurity." However, in practice, moving to a non-standard port like 2222 or 4433 reduces the noise in your logs by 95%, as most automated botnets only scan the default port. This allows your security team to focus on legitimate threats rather than thousands of failed "admin/admin" attempts.
Implementing Connection Rate Limiting
We can use the built-in MaxStartups directive to throttle incoming connections. This is particularly effective against distributed brute-force attacks that attempt many simultaneous connections.
# Format is 'start:rate:full'
Drop 30% of connections if there are 10 unauthenticated connections,
and 100% if there are 60.
MaxStartups 10:30:60 MaxAuthTries 3
Configuring Idle Timeout Intervals
Stale SSH sessions are a major risk, especially if a developer leaves a terminal open on an unattended laptop. We enforce server-side timeouts to terminate inactive connections.
# Send a 'keep-alive' signal every 5 minutes.
If the client doesn't respond, terminate immediately.
ClientAliveInterval 300 ClientAliveCountMax 0
Setting ClientAliveCountMax to 0 ensures that the session is killed the moment a single timeout interval is missed, preventing "zombie" sessions from persisting.
Advanced SSH Hardening Techniques
In a multi-cloud environment, you likely have different teams (DevOps, DBAs, SREs) requiring different levels of access. Instead of allowing any user with a shell to SSH in, we use AllowGroups to create a strict whitelist.
# Only users in the 'iam-bastion-admins' group can connect
AllowGroups iam-bastion-admins
Integrating Multi-Factor Authentication (MFA)
For high-security environments, SSH keys alone are insufficient. We must implement a second factor. The libpam-google-authenticator module is a reliable way to add Time-based One-Time Passwords (TOTP) to the SSH workflow.
# Install the PAM module on Ubuntu/Debian
sudo apt-get install libpam-google-authenticator
Configure PAM by adding this to /etc/pam.d/sshd
auth required pam_google_authenticator.so
After configuring PAM, you must update sshd_config to allow both the public key and the keyboard-interactive (MFA) step.
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
Mitigating Brute Force with Fail2Ban
Fail2Ban monitors your log files and dynamically updates your firewall (iptables/nftables) to ban IP addresses that exhibit malicious behavior. For an Indian enterprise, this is essential to block the constant scanning originating from compromised global proxy nodes.
# /etc/fail2ban/jail.local configuration for SSH
[sshd] enabled = true port = 2222 filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 1h findtime = 10m
I frequently see configurations where findtime is too short. Increasing it to 10 or 20 minutes catches slower, more methodical brute-force attempts that try to stay under the radar.
Monitoring and Auditing for Compliance
The CERT-In Cyber Security Directions of April 2022 mandate that all corporate entities maintain ICT system logs for 180 days. For an SSH bastion, this means every login, logout, and failed attempt must be offloaded to a central logging server or a dedicated SIEM to prevent an attacker from wiping their tracks locally.
Reviewing Logs for Anomalies
We use journalctl to extract actionable intelligence from the SSH service. One of my standard checks is identifying the IP addresses with the highest failure rates in the last hour.
# Extract unique IPs attempting brute-force in the last hour
journalctl -u ssh --since "1 hour ago" | grep "Failed password" | awk '{print $NF}' | sort | uniq -c | sort -nr
If you see an IP from a region where you have no developers (e.g., an IP from a data center in a country where your team doesn't operate), it should be blacklisted at the Cloud Security Group level immediately.
Automating Security Hardening Audits
Manual audits are prone to error. I use nmap scripts to verify the effective cryptographic policy of the bastion from an external perspective. This ensures that what we think is configured in sshd_config is actually what the service is presenting to the world.
$ nmap -p 2222 --script ssh2-enum-algos 10.0.1.50
PORT STATE SERVICE 2222/tcp open EtherNetIP-1 | ssh2-enum-algos: | kex_algorithms: (2) | [email protected] | diffie-hellman-group-exchange-sha256 | server_host_key_algorithms: (1) | ssh-ed25519 | encryption_algorithms: (2) | [email protected] | [email protected] | mac_algorithms: (2) | [email protected] |_ [email protected]
If the output shows ssh-rsa or hmac-sha1, the hardening has failed or there is a conflicting configuration file in /etc/ssh/sshd_config.d/.
Ongoing Maintenance and Patching
In the context of the Indian IT landscape, many SMEs utilize local VPS providers that provide static OS images. These images can be months or years out of date. We must automate the patching of the openssh-server package.
# Create a cron job to check for security updates daily
echo "0 2 * root apt-get update && apt-get install --only-upgrade openssh-server -y" > /etc/cron.d/ssh-patch
This ensures that critical fixes for vulnerabilities like RegreSSHion are applied within 24 hours of release, regardless of manual intervention.
Verifying Host Identity to Prevent MitM
One often overlooked aspect of SSH security is the verification of host keys. When a user connects to a bastion for the first time, they are prompted to accept a fingerprint. If an attacker is performing a Man-in-the-Middle (MitM) attack, they can present their own key. We must distribute the legitimate host key fingerprints to all team members via a secure out-of-band channel.
# Generate the SHA256 fingerprint of the bastion's public Ed25519 host key
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
This output (e.g., SHA256:nC8...) should be documented in your internal security portal. Developers should be trained to never type "yes" to the SSH prompt unless the fingerprint matches this known value.
Next Command: Runtime Configuration Validation
To ensure your hardening changes are active without restarting the service (which could drop active connections), use the test mode of sshd. This validates the syntax and shows the effective configuration.
sshd -T | grep -E "permitrootlogin|passwordauthentication|ciphers"
If this command returns permitrootlogin yes, your configuration is not being loaded correctly, likely due to a syntax error in an include file. Fix this before proceeding with your deployment.
