banner
Aki

Aki

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

safely-bash

Safely running a public-facing server's bash

SSH Access Protection#

SSH, as an important entry point for bash, is very dangerous when exposed directly to the public network on the default port 22. It can result in data loss and financial loss💔, or even become a tool for others to exploit😨. Therefore, how to securely access the bash of a cloud server has become a significant challenge⁉️.

Modify the port and login permissions. The default port 22 should be changed to a non-standard port, and password login should be disabled❌, using key-based🔑 authentication instead.

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

Enable Firewall Protection#

In general, cloud platforms provide basic platform firewalls, combined with host firewalls, to resist certain intrusion attacks.

Firewall restrictions on source access. For users or companies with fixed public network🌏 IP addresses, restricting source access on the host firewall 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 settings:

> ufw allow from client IP to any port SSH port

For iptables firewall settings:

> iptables -A INPUT -p tcp --dport SSH port -s client IP -j ACCEPT

Restrict Access from Dynamic Public IP Addresses#

For users without fixed public IP addresses or dedicated lines, dynamic access restriction from source IP addresses can be achieved using DDNS and bash scripts. The principle is shown in the following diagram👇:

image

First, you need to 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 can be considered as reverse DDNS). 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 duplication
    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 need to update" >> $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 of the domain name.

End, celebration🎊.

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