Additional OpenSSH Security
Allowed Users
For added security, we can specify users who are allowed to log in using SSH
Edit the /etc/ssh/sshd_config file and add the following two lines right after the Authentication section of the file:
Code:
# Users allowed access
AllowUsers radar avalon
So now we have excluded all other accounts from being valid users. The ssh daemon will throw an error in it's log file when any other account is tried.
TCP_Wrappers
We will establish a default deny policy for sshd and only allow IP addresses and networks that we specify in the access control list files.
These two files are: /etc/hosts.deny and /etc/hosts.allow. There's a certain degree of flexibility in how you can use tcp_wrappers including: You can use both files or just one. You can format the rules the way that is best for you.
Here I will show how to use both hosts.deny and hosts.allow, and I will use a rule format that's easier for me to manage.
The default deny
edit /etc/hosts.deny and add the sshd rule
Code:
# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
# See the manual pages hosts_access(5), hosts_options(5)
# and /usr/doc/netbase/portmapper.txt.gz
#
# Example: ALL: some.host.name, .some.domain
# ALL EXCEPT in.fingerd: other.host.name, .other.domain
#
# If you're going to protect the portmapper use the name "portmap" for the
# daemon name. Remember that you can only use the keyword "ALL" and IP
# addresses (NOT host or domain names) for the portmapper. See portmap(8)
# and /usr/doc/portmap/portmapper.txt.gz for further information.
#
# The PARANOID wildcard matches any host whose name does not match its
# address.
# You may wish to enable this to ensure any programs that don't
# validate looked up hostnames still leave understandable logs. In past
# versions of Debian this has been the default.
# ALL: PARANOID
sshd : ALL : DENY
portmap: ALL :deny
There should be a carriage return at the end of the file
Explicit allows
Edit /etc/hosts.allow
Code:
# /etc/hosts.allow: list of hosts that are allowed to access the system.
# See the manual pages hosts_access(5), hosts_options(5)
# and /usr/doc/netbase/portmapper.txt.gz
#
# Example: ALL: LOCAL @some_netgroup
# ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
#
# If you're going to protect the portmapper use the name "portmap" for the
# daemon name. Remember that you can only use the keyword "ALL" and IP
# addresses (NOT host or domain names) for the portmapper, as well as for
# rpc.mountd (the NFS mount daemon). See portmap(8), rpc.mountd(8) and
# /usr/share/doc/portmap/portmapper.txt.gz for further information.
#
sshd : \
192.168.0.0/255.255.255.0 \
xx.0.0.0/255.248.0.0 \
xx.8.0.0/255.252.0.0 \
xx.12.0.0/255.254.0.0 \
xx.14.0.0/255.255.0.0 \
: allow
portmap: 192.168.0.4,192.168.0.2 :ALLOW
The man page for hosts_access explains the rule structure and formatting options. Generally though, you can verify that sshd is compiled with the proper support for tcp_wrappers this way:
Code:
saturn:~# strings -f /usr/sbin/sshd | grep access
/usr/sbin/sshd: hosts_access
/usr/sbin/sshd: @(#)$OpenBSD: groupaccess.c,v 1.6 2003/04/08 20:21:28 itojun Exp $
/usr/sbin/sshd: userauth_hostbased: access allowed by auth_rhosts2
/usr/sbin/sshd: It is recommended that your private key files are NOT accessible by others.
The line we're interested in contains hosts_access
Reasoning
Why do we do all this? It is a decent way, IMHO, to thwart brute force attempts against your host accounts. Without this, you probably see logs upon logs of failed password attempts, and we'll see that LogWatch now contains the failed attempts:
Before
Code:
--------------------- SSHD Begin ------------------------
Didn't receive an ident from these IPs:
4h134234.aspadmin.net (216.98.134.234): 1 Time(s)
serv-1-0-130.lycos-vds.com (84.244.0.130): 1 Time(s)
Illegal users from these:
ace/none from ::ffff:216.98.134.234: 1 Time(s)
alex/none from ::ffff:84.244.0.130: 1 Time(s)
ana/none from ::ffff:84.244.0.130: 1 Time(s)
andrea/none from ::ffff:84.244.0.130: 1 Time(s)
andrew/none from ::ffff:84.244.0.130: 1 Time(s)
angel/none from ::ffff:84.244.0.130: 1 Time(s)
anonymous/none from ::ffff:216.98.134.234: 1 Time(s)
bank/none from ::ffff:84.244.0.130: 1 Time(s)
barbara/none from ::ffff:84.244.0.130: 1 Time(s)
betty/none from ::ffff:84.244.0.130: 1 Time(s)
billy/none from ::ffff:84.244.0.130: 2 Time(s)
bob/none from ::ffff:84.244.0.130: 1 Time(s)
brandon/none from ::ffff:84.244.0.130: 1 Time(s)
brian/none from ::ffff:84.244.0.130: 1 Time(s)
buddy/none from ::ffff:84.244.0.130: 1 Time(s)
carmen/none from ::ffff:84.244.0.130: 1 Time(s)
charlie/none from ::ffff:84.244.0.130: 1 Time(s)
~
~
~
After
Code:
Refused incoming connections:
::ffff:140.136.200.137 (::ffff:140.136.200.137): 2 Time(s)
::ffff:202.181.183.4 (::ffff:202.181.183.4): 2 Time(s)
::ffff:211.136.20.50 (::ffff:211.136.20.50): 1 Time(s)
::ffff:58.159.67.245 (::ffff:58.159.67.245): 1 Time(s)
This method also gives you a layered approach to your remote access security:
- We now disallow insecure protocols
- We disallow direct root access to the SSH daemon
- We force the use of secure keys for SSH access
- We have a list of allowed users of SSH
- We have a host-based access list ACL that at least makes it far more difficult to gain an unauthorized connection to the SSH daemon
Bookmarks