To block outgoing SSH connections for specific users on Ubuntu, use the
iptables firewall to restrict outbound traffic on port 22 based on user IDs. This method leverages the owner match module in netfilter to apply rules directly to processes initiated by designated accounts, ensuring that only authorized services or administrators can initiate external SSH sessions while maintaining system-wide connectivity for others.
Understanding User-Based Firewall Rules
Standard firewall rules typically filter traffic based on source IP addresses or destination ports. However, when you need to control access at the application level rather than the network level, you must inspect the packet's origin within the kernel. Linux provides a powerful mechanism through the
iptables service, specifically the
-m owner extension. This module allows you to match packets generated by local applications against the user ID (
UID) or group ID (
GID) of the process creating them. By targeting the
OUTPUT chain, which handles packets leaving the server, you can effectively prevent specific users from establishing new outbound SSH connections without affecting the ability of other users or system services to do so.
Identifying Target Users and Ports
Before configuring the firewall, you must identify the exact user accounts that require restrictions. You can find the numeric User ID associated with a username by using the
id command. For example, running
id username will output the UID and GID. Note that
iptables rules generally work with numeric UIDs rather than string usernames. Additionally, standard SSH uses TCP port 22. If your environment uses non-standard ports, you must adjust the rule accordingly. It is crucial to verify that the target users are not part of the
sudo group if you intend to allow administrative overrides later, although the rule itself applies strictly to the specified UID.
Configuring iptables for Specific Users
The core solution involves adding a rule to the
OUTPUT chain of the
filter table. The following command blocks outgoing TCP traffic on port 22 for a specific user ID. Replace
1001 with the actual UID of the user you wish to restrict.
sudo iptables -A OUTPUT -p tcp --dport 22 -m owner --uid-owner 1001 -j DROP
This command appends (-A) a rule to the OUTPUT chain. It specifies the protocol as TCP (-p tcp) and the destination port as 22 (--dport 22). The critical component is
-m owner --uid-owner 1001, which tells the kernel to only apply this rule to packets originating from the process owned by UID 1001. The final flag,
-j DROP, instructs the firewall to silently discard these packets, preventing the connection attempt from reaching the remote server. If you want to explicitly reject the connection with an error message instead of dropping it silently, you can use
-j REJECT with
--reject-with icmp-port-unreachable.
It is important to note that this rule does not affect incoming SSH connections to the server. Those are handled by the
INPUT chain. Furthermore, this restriction applies to new connections. Existing established connections will continue until they are closed, as they are tracked by stateful inspection modules like
conntrack. To ensure this rule persists across reboots, you should save your current iptables configuration. On modern Ubuntu systems using
nftables backend or traditional
iptables-persistent, the saving method may vary. Using
iptables-persistent is straightforward:
sudo netfilter-persistent save
If your system does not have
netfilter-persistent installed, you may need to install it via
apt install iptables-persistent. This ensures that your security policies remain intact after a system restart.
Verifying and Troubleshooting
After applying the rule, verify its presence by listing all rules in the OUTPUT chain. Use the following command to see detailed information including packet counts:
sudo iptables -L OUTPUT -v -n
Look for a line corresponding to your user's UID and port 22. The "pkts" column indicates how many packets have been matched and dropped. If the count increases when the restricted user attempts an SSH connection, the rule is working correctly. If it does not increase, check if there are any earlier rules in the chain that might be accepting or dropping traffic before this rule is evaluated. Rule order matters;
iptables processes rules sequentially. If you need to insert a rule at a specific position, use
-I (Insert) instead of
-A (Append), specifying the line number.
For troubleshooting, ensure that the user is actually generating the traffic. Sometimes, services running under different users might proxy connections. Also, remember that root (UID 0) is not affected unless you explicitly add a rule for UID 0. This approach complements broader security measures discussed in related guides, such as those found in
Understanding Ubuntu 22.04 VPS Security, by adding granular control over user privileges.
Frequently Asked Questions
Does this block incoming SSH connections?
No, this rule only affects outgoing traffic initiated by the specified user. Incoming SSH connections to the server are managed by the INPUT chain and are unaffected by OUTPUT rules. To restrict incoming access, you would need to modify rules in the INPUT chain or use
sshd_config settings.
Will this stop sudo commands from working?
No, because
sudo elevates privileges to root (UID 0). Unless you explicitly create a rule blocking UID 0, the elevated process will not be subject to the UID-specific drop rule. However, if the user runs an SSH client directly without
sudo, it will be blocked.
How do I remove the rule?
You can delete the rule by identifying its line number in the OUTPUT chain using
iptables -L OUTPUT --line-numbers. Then, run
sudo iptables -D OUTPUT [line_number]. Alternatively, you can flush the entire OUTPUT chain with
sudo iptables -F OUTPUT, but this removes all outbound restrictions.
Can I block SSH for a group of users?
Yes, you can use the
--gid-owner option instead of
--uid-owner. For example,
-m owner --gid-owner developers will block all members of the "developers" group. Ensure the group exists and has a valid GID before applying the rule.
What happens if I reboot the server?
By default,
iptables rules are stored in memory and are lost upon reboot. You must save the rules using
netfilter-persistent save or a similar persistence mechanism provided by your distribution. Without saving, the restrictions will disappear after a restart, potentially exposing the system to unintended outgoing connections.