When configuring SSH access control, many administrators need to enforce different behaviors based on the client's origin network. The specific requirement here involves forcing a particular command for external connections while allowing normal SSH access for LAN users.
The OpenSSH configuration file uses Match blocks with conditions like Address to apply specific settings. However, negating these conditions isn't as straightforward as one might expect:
# These attempts don't work as intended:
Match Address !192.168.1.0/24
ForceCommand /path/to/restricted_shell
Match Address !192.168.*
ForceCommand /path/to/restricted_shell
# This syntax causes sshd to fail:
Match !Address 192.168.*
ForceCommand /path/to/restricted_shell
The proper way to implement this is by using multiple Match blocks with the All condition:
# First block - allow full access for LAN
Match Address 192.168.1.0/24
# No ForceCommand means normal access
# Second block - restrict all others
Match All
ForceCommand /path/to/restricted_shell
While not directly supported in Address conditions, you can use exclamation marks in more specific patterns:
# This works for specific IP negation
Match Address !192.168.1.5,!192.168.1.6
ForceCommand /path/to/restricted_shell
Here's a complete example that combines both approaches:
# Global settings
Port 22
PermitRootLogin no
PasswordAuthentication no
# Allow full access for LAN
Match Address 192.168.1.0/24,10.0.0.0/8
PermitRootLogin prohibit-password
X11Forwarding yes
# Restrict all other connections
Match All
ForceCommand /usr/local/bin/restricted_shell
PermitTTY no
X11Forwarding no
AllowTcpForwarding no
After making changes, always test your configuration:
sudo sshd -t # Check for syntax errors
sudo systemctl restart sshd
Test from both internal and external networks to verify the behavior matches your expectations.
When implementing forced commands:
- Ensure the restricted shell can't be bypassed
- Consider additional protections like two-factor authentication
- Log all restricted access attempts
- Regularly audit the forced command implementation
When configuring SSH server security, administrators often need to enforce different policies based on the source network. The requirement to apply a ForceCommand
only for connections originating outside a specific LAN (while allowing normal access within the LAN) presents an interesting configuration challenge.
From the attempts mentioned:
# These didn't work as expected
Match Address !192.168.1.0/24
ForceCommand /path/to/restricted_shell
Match Address !192.168.*
ForceCommand /path/to/restricted_shell
# This caused sshd to fail
Match !Address 192.168.*
ForceCommand /path/to/restricted_shell
To properly negate address patterns in sshd_config
, you need to use the negation syntax correctly within a single Match
block:
# Working solution for OpenSSH
Match Address *,!192.168.*,!10.0.*
ForceCommand /path/to/restricted_shell
Key points to remember:
- The comma-separated list allows multiple patterns (both positive and negative)
- The initial wildcard (
*
) matches all addresses before exclusions - Order matters - exclusions should come after the wildcard
Here's a full example that implements this properly:
# /etc/ssh/sshd_config
# Allow full access for LAN users
Match Address 192.168.0.0/16,10.0.0.0/8
PermitTTY yes
X11Forwarding yes
# Restrict external users to a specific command
Match Address *,!192.168.*,!10.*
ForceCommand /usr/local/bin/restricted-shell
PermitTTY no
X11Forwarding no
AllowTcpForwarding no
Always verify your changes:
sudo sshd -t && sudo systemctl restart sshd
Test from both internal and external networks to confirm the restrictions apply correctly.
For more complex scenarios, consider:
- Using
iptables/nftables
for network-level restrictions - Implementing
Match LocalPort
with different ports for internal/external access - Combining
Match Group
with address conditions for user-specific policies