banner
Aki

Aki

太阳能维修,月亮可更换,星星不闪包退换。
twitter

safely-bash

Safely running a public-facing server's bash

Protection for SSH Access#

Exposing SSH directly to the public network on the default port 22 is a highly dangerous practice. It can result in data loss and financial damages💔, or even turn the server into a tool for malicious activities😨. Therefore, securely accessing a cloud server's bash has become a significant challenge⁉️.

Changing the Port and Login Permissions
The default port 22 should be changed to a non-standard port, and password login should be disabled❌ in favor of key-based authentication🔑.

> vim /etc/ssh/sshd_config
Port Non-standard Port
PasswordAuthentication no
PubkeyAuthentication yes

Enabling Firewall Protection
In general, cloud platforms provide basic platform firewalls, which, combined with host firewalls, can withstand certain intrusion attacks.

Firewall restrictions on source access
For users or companies with fixed public🌏 IP addresses, restricting source access at the host firewall level is sufficient. Here are the firewall settings for firewalld:

> firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="Client IP" port protocol="tcp" port="SSH Port" accept' --permanent

For ufw firewall:

> ufw allow from Client IP to any port SSH Port

For iptables firewall:

> iptables -A INPUT -p tcp --dport SSH Port -s Client IP -j ACCEPT

Limiting Access from Dynamic Public IPs
For users without fixed public IPs or dedicated lines, dynamic access restrictions can be implemented using DDNS and bash scripts. The principle is shown in the following diagram👇:

image

First, purchase a domain name, which can be a free one. Common DDNS tools include Alibaba Cloud DDNS, Tencent DDNS, ddns-go, etc.

Next, write a script to obtain the dynamic IP address pointed to by the domain name (similar to DDNS, but in reverse). Taking ufw firewall as an example:

#!/bin/bash

# Initialize variables
current_time=$(date "+%Y-%m-%d %H:%M:%S")
DOMAIN="Your Domain"
DOMAIN_IP=$(nslookup $DOMAIN | awk '/^Address: / { print $2 }')
LOG_FILE="/var/log/ufw_update.log"
PORT="Server's SSH Port"

# Extract the last recorded IP from the log file
if [ -f "$LOG_FILE" ]; then
    LAST_IP=$(grep "DOMAIN-IP:" $LOG_FILE | tail -1 | awk '{print $NF}')
else
    LAST_IP=""
fi

# Update the log file
echo "$current_time: Current DOMAIN-IP: $DOMAIN_IP" >> $LOG_FILE

# Check if the IP has changed or the log file does not exist
if [ "$DOMAIN_IP" != "$LAST_IP" ] || [ -z "$LAST_IP" ]; then
    echo "$current_time: IP address has changed, updating" >> $LOG_FILE

    # Update UFW rules
    # Delete all rules for the specified port to avoid duplicates
    ufw status numbered | grep " $PORT " | cut -d "[" -f2 | cut -d "]" -f1 | tac | while read -r line ; do
        yes | ufw delete $line
    done
    # Add new rule
    ufw allow from $DOMAIN_IP to any port $PORT
    ufw deny $PORT

    echo "$current_time: Update completed" >> $LOG_FILE
else
    echo "$current_time: IP address has not changed, no update needed" >> $LOG_FILE
fi

# Print the current firewall status
ufw_status=$(ufw status)
echo "$current_time: Current firewall status:" >> $LOG_FILE
echo "$ufw_status" >> $LOG_FILE
echo "===============================" >> $LOG_FILE

Finally, set up a crontab schedule😄 to execute the script and obtain the IP address resolved by the domain name.

That's it, celebration time! 🎊

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.