I have an Internet server which accepts ssh connections from the Internet. I want to lock down Internet connections more tightly, while leaving connections from the local network a bit more open.

On Mac OS X, the way to do this is through the Match directive in /etc/sshd_config. Unfortunately, RHEL/CentOS 5 & SLES 10 include openssh v4.x, which lacks the Match directive.

Things are complicated by multiple overlapping directives to control password authentication in OpenSSH, which behave differently on different platforms. But the OpenSSH developers have suggested global settings in /etc/sshd_config like:

Protocol 2
ChallengeResponseAuthentication no
PasswordAuthentication no
KbdInteractiveAuthentication no

And overrides along the lines of:

Match 10.0.0.0/8
  PasswordAuthentication yes
  KbdInteractiveAuthentication yes

On CentOS Match isn't available, so we run two different sshd daemons. Here's the init script that runs them both (I couldn't just copy and tweak one, because they'd interfere with each other):

[root@c54 ~]# diff -u /etc/init.d/sshd.c54 /etc/init.d/sshd
--- /etc/init.d/sshd.c54    2009-10-26 19:47:06.000000000 -0400
+++ /etc/init.d/sshd    2009-11-02 13:02:24.000000000 -0500
@@ -96,6 +96,12 @@
        failure $"Configuration file or keys are invalid"
        echo
    fi
+   $SSHD -t -f /etc/ssh/sshd_config.222
+   RETVAL=$?
+   if [ ! "$RETVAL" = 0 ]; then
+       failure $"External configuration file or keys are invalid"
+       echo
+   fi
 }

 start()
@@ -108,7 +114,7 @@
    cp -af /etc/localtime /var/empty/sshd/etc

    echo -n $"Starting $prog: "
-   $SSHD $OPTIONS && success || failure
+   $SSHD $OPTIONS && PID_FILE=$PID_FILE_EXT $SSHD -f /etc/ssh/sshd_config.222 $OPTIONS && success || failure
    RETVAL=$?
    [ "$RETVAL" = 0 ] && touch /var/lock/subsys/sshd
    echo
@@ -117,11 +123,7 @@
 stop()
 {
    echo -n $"Stopping $prog: "
-   if [ -n "`pidfileofproc $SSHD`" ] ; then
-       killproc $SSHD
-   else
-       failure $"Stopping $prog"
-   fi
+   killall $SSHD
    RETVAL=$?
    # if we are in halt or reboot runlevel kill all running sessions
    # so the TCP connections are closed cleanly

Their configurations are slightly different:

[root@c54 ~]# diff -u /etc/ssh/sshd_config /etc/ssh/sshd_config.222 
--- /etc/ssh/sshd_config    2009-11-02 16:59:40.000000000 -0500
+++ /etc/ssh/sshd_config.222    2009-11-02 16:59:46.000000000 -0500
@@ -57,7 +57,7 @@
 # To disable tunneled clear text passwords, change to no here!
 #PasswordAuthentication yes
 #PermitEmptyPasswords no
-#PasswordAuthentication yes
+PasswordAuthentication yes

 # Change to no to disable s/key passwords
 #ChallengeResponseAuthentication yes
@@ -119,5 +119,5 @@
 Subsystem  sftp    /usr/libexec/openssh/sftp-server


-# sshd for external (Internet) connections: no passwords allowed
-PasswordAuthentication no
+# sshd for internal (campus) connections: passwords allowed
+Port 222

The intelligent switching occurs in /etc/sysconfig/iptables, which redirects internal connections to the alternat port (and thus daemon). Unfortunately, due to the way iptables works, 'trusted' connections must be both REDIRECTed and ACCEPTed:

*nat
:PREROUTING ACCEPT
:POSTROUTING ACCEPT
:OUTPUT ACCEPT

-A  PREROUTING -p tcp --dport    22 -s 10.0.0.0/24    -j REDIRECT --to-port   222
# Connections from 10.0.0. are more trusted, so send them to the private sshd on port 222.
# Each subnet must also be ACCEPTed below.

COMMIT


*filter
:INPUT DROP
:FORWARD DROP
:OUTPUT ACCEPT

-A INPUT -j ACCEPT -i lo
-A INPUT -j DROP                       -s 127.0.0.0/8
-A INPUT -j DROP                       -d 127.0.0.0/8
# Allow loopback connections, but drop forged pseudo-local packets

-A INPUT -j ACCEPT -m state --state RELATED,ESTABLISHED
# Continue established connections


-A INPUT -j ACCEPT -p tcp --dport    22
# sshd on port  22, for Internet connections (no passwords)

-A INPUT -j ACCEPT -p tcp --dport   222 -s 10.0.0.0/24
# sshd on port 222, for trusted connections
# Each subnet must also be REDIRECTed above.

COMMIT