tperimeter
- A Dynamic TCP Wrapper Control Systemtperimeter
is a system that provides a secure mechanism for remotely
opening access to internet services under TCP Wrapper control. Consider the
following very typical scenario:
An internet-facing server is configured with a variety of services that observe TCP Wrapper (/etc/hosts.allow
) access control rules. It is common to use this mechanism to very strictly limit which external IP addresses may even attempt connection to these services. For instance, we may choose to limitssh
logins from IPs of hosts known to us. The problem with this is that legitimate users whose IP addresses may change will not be able to connect. This is common when a user travels and uses internet connections in airports, hotels, or other places wheredhcp
is used for dynamic IP assignment. In this case, the user has no a priori knowledge of what his IP address will be and thus cannot have it added to/etc/hosts.allow
to enable remote system access.
A number of solutions to this problem have been proposed such as VPNs
and so-called "port knocking", but they are complex and require some
level of custom client code. tperimeter
uses open-source tools to
solve the problem simply and elegantly. A traveling user or a user
whose IP address changes regularly simply logs into a secure web page
and informs the system of their current IP address and which services
they'd like to have enabled for them. tperimeter
then fulfills
the request - typically within 1 minute or so - and grants access to
the system for that service from that IP address for a small window in
time - 10 minutes is typical. This gives the user time to access the
desired service before TCP Wrappers once again close the system to its
default state. These semantics thus provide flexible remote access
with an automatic reset to system default access control.
tperimeter
WORKStperimeter
has two major components:
- A requestor subsystem that presents the user a web page to request a "hole" be opened in the TCP wrappers for a specific service from a particular IP address. This request is then enqueued on disk for subsequent processing.
- A TCP wrapper rewrite mechanism that periodically (under
cron
control) rebuilds the/etc/hosts.allow
file to reflect any pending user requests queued by the requestor subsystem.
The workflow is fairly simple:
- The user logs into the
tperimeter
web interface and specifies from what IP address and to which service they want access.- A
cron
job periodically runs to process any such pending requests by dynamically rewriting thehosts.allow
file.- The
cron
job then deletes the request from thetperimeter
queue, but only if it has exceeded a certain age. This age is specified in therebuild-hosts.allow.sh
file with the${DURATION}
variable. This means that the next timehosts.allow
is rebuilt by thecron
job, old "holes"tperimeter
opened in the TCP wrappers will be removed. This ensures that someone doesn't open a hole in the system that then stays there permanently. This works fine in practice, because the TCP wrapper security model operates only at the time of the initial connection request. Thetperimeter
semantics were designed to open a hole only long enough to allow the user to make the initial connection - that will stay in place even after the wrappers are closed back up to their default state. For example, you can open access withtperimeter
to gain access for, say,ssh
. Once you've made the connecton, it remains connected even afterhosts.allow
is rebuilt to its default closed state.
The requestor subsystem consists of two parts. tperimeter-ui.html
is the web interface for the user to specify the service and IP
address they want opened. tperimeter.py
is a CGI script that
parses the user's input and actually places it on the disk queue for
subsequent processing.
rebuild-hosts.allow.sh
is the TCP wrapper rewrite mechanism.
After a user has requested access, they must wait until this
script runs again before the access is actually granted. So, this
should be run in the root crontab
every minute.
The queue where tperimeter
requests are initially deposited and
subsequently processed is transparent to the user and requires no
administration by the system administrator. The queue is created by
the web interface when a request is made. It is then subsequently
processed by the TCP wrapper rewrite mechanism and then deleted as
described above.
Each request tperimeter
receives is logged in the system log.
It is in the form:
Sep 25 13:37:11 myhost tperimeter: User@192.168.0.2 Requested Service: sshd For Address: 10.0.1.23
tperimeter
This section provides an overview of how tperimeter
is installed.
It assumes you are a capable systems administrator and does not go
into the minutae of permissions, file ownership and so forth.
In general, the requestor files should be owned by the web daemon
(usually www
) The wrapper rewrite script should be owned by
root
. These files should have permissions of 700
or possibly
740
. The file tree that describes the default wrapper
configuration should only be writable by root
. If you're
particularly paranoid and don't want local users to know what your
default wrappers look like, you can also make this file tree only
readable by root
as well. And, of course, tperimeter.py
and rebuild-hosts.allow.sh
should be set as executable by
their respective owners.
First, you have to install the web interface. The example here
assumes you're using apache
:
Install
tperimeter-ui.html
in your desired location on the web site. We'll use/www/RemoteAccess
for our example.You can either rename it to
index.html
(ugly) or symlink to it (better):ln -s tperimeter-ui.html index.html
You probably don't want the whole world to have access to this service, so it's pretty much mandatory you use password access to the system. With
apache
this means you'll need to install an appropriate.htaccess
file in this directory or otherwise secure it in yourapache
configuration file.It is highly recommended that you require
https
when accessing this URL. There's no point in securing your system if the password is flowing in plain text over the internet. So, when you're done, the user will gain access totperimeter
at:https://your.fine.website.com/RemoteAccess
Now, you need to install the CGI script:
In your web site's
cgi-bin
directory, create a directory calledtperimeter
.Copy
tperimeter.py
to this directory. This script requires a fairly recent copy ofpython
on your system. As written, it assumes that it is in/usr/local/bin/python
, so you may need to modify the script if your system has thepython
binary somewhere else.Now (very important) symlink the
.htaccess
file you created in the previous step for the web interface to this directory. This prevents Eeeeeeevil Hackers from running the requestor script directly from a URL and bypassing your website security:ln -s /www/RemoteAccess/.htaccess .htaccess
Next, you need to install the TCP wrapper rewrite subsystem:
Create the directory:
mkdir -p /usr/local/etc/tperimeter
Copy the
rebuild-hosts.allow.sh
file to this directory.
Now, you have to create the entries that describe your "default" TCP
wrapper configuration. tperimeter
has to know how to build your
"standard" TCP wrapper file - i.e., The hosts.allow
entries you
always want in place regardless whether or not there is pending
requests for temporary access via the web interface. That's because
rebuild-hosts.allow.sh
runs periodically under cron
control and
rebuilds the entire hosts.allow
file.
To make this simple, the list of things you always want in your
hosts.allow
file is represented by a directory tree with
zero-length files in it. tperimeter
uses the names of these
directories and files to build the default TCP wrapper file. This is
a fairly standard Unix idiom - using the file namespace to represent
some larger behaviorial semantic. This file tree is also found in
/usr/local/etc/tperimeter
. You'll find an example of what goes
where in the tperimeter-sample
directory included in this
distribution that may be helpful as you study the following material.
The
prologue
andepilogue
files are simply copied respectively to the beginning and end of yourhosts.allow
file. You can put any custom wrapper statements in these files as needed.The
allow
anddeny
directories contain entries for specific services you wish to allow or deny. You create a directory under these for each service you want to control. Within that "service directory" you create (usingtouch
) one or more zero-length files that are named with the IP address or DNS name of the host you are allowing/denying.Say you want to allow
ssh
access from 64.2.3.1 and anyone in 10.0.1.x, and denyftp
access from everyone. Then the directory/file layout would look like this:/usr/local/etc/tperimeter/ allow/ sshd/ 10.0.1. 64.2.3.1 deny/ ftpd/ ALL
Note that
10.0.1.
,64.2.3.1
, andALL
are names of zero-length files easily created with thetouch
utility.When
hosts.allow
get's rebuilt, this would result in two wrapper statements:ftpd: ALL :DENY sshd: 10.0.1. 64.2.3.1 :ALLOW
When rebuild-hosts.allow.sh
runs under cron
control it will
scan this directory structure. First, it will emit any pending
tperimeter
access requests. Then it will emit your prologue
.
Then it will process your deny
entries in the format just
described. Then it will do the same for your allow
entries.
Finally, it will emit your epilogue
. You should keep several
things in mind when laying out your individual allow/deny entries:
- All
deny
entries are processed before yourallow
entries. This means thedeny
statements will appear before anyallow
entries in yourhosts.allow
file.- The entries in a given service directory are processed in alphanumeric order and will appear in your
hosts.allow
in that same order.- Take care to name your service directories properly. They are named for the service not the client program that accesses it.
ssh
access is in a directory namedsshd
,ftp
inftpd
and so on.
Once you get the hang of this, it is really simple to administer. To
add or deny access for a particular host, just go to the service
directory in question and touch
a file by that name. To remove
access or denial, go to the directory and delete the file by that
name. Thereafter, when rebuild-hosts.allow.sh
runs again, it will
build a new TCP wrapper control file with your new settings.
You can see what your changes will look like by running
rebuild-hosts.allow.sh
manually. By default, it emits output
to stdout
. You can even rebuild the hosts.allow
file yourself
if you don't want to wait for cron
to do it:
/usr/local/etc/tperimeter/rebuild-hosts.allow.sh >/etc/hosts.allow
Finally, you need to create a cron
job that runs the TCP wrapper
rebuilding process regularly:
# Update /etc/hosts.allow to accommodate any tperimeter requests
0,10,20,30,40,50 * * * * /usr/local/etc/tperimeter/rebuild-hosts.allow.sh >/etc/hosts.allow
tperimeter
The tperimeter-ui.html
file provided with this distribution is
very simple and contains the login banner and greeting message the
user sees when they authenticate and gain access to the tperimeter
system. You can modify this file to suit your taste and otherwise
match the look-and-feel of your web site.
You can modify the tperimeter.py
file to indicate which services
may be accessed with tperimeter
. You can also modify this file
to list any IP addresses that are never allowed access. As a
practical matter, you typically only need provide access to sshd
for almost anything one would like to do remotely.
There are a few things that can bite you when using tperimeter
:
The requestor/rewrite systems work off a common disk queue without any access locking. This means it is theoretically possible to get a race condition wherein the user queues a request just as the rewrite system finishes running and deletes the queue. In this case, the user's request will never be fullfilled, and they'll have to request access again.
Similarly, there is no locking done when the
hosts.allow
file is rewritten. The script that produces the new version of this file simply overwrites it. There is the possibility that, at the moment that file is being created, someone will attempt to access your system when there are no TCP wrapper rules in effect. In designing this system, it was felt that this exposure was quite low. If this turns out not to be the case (remember, this is EXPERIMENTAL software), then thehosts.allow
rewrite mechanism will have to be rewritten to make sure that there is always some level of protection in place as the file is being modified. If you have comments or experience with such problems - or better still, can provide a better mechanism - please contact us at the email address found below.Some (many) dynamic DNS systems found in hotels, airports, and the like do not properly match forward and reverse DNS entries. If you use strict DNS rules in your
hosts.allow
file with and entry likeALL : PARANOID : RFC931 20 : DENY
, this would prevent access from such addresses even though they've been granted bytperimeter
. For this reason, the wrapper rewrite script places anytperimeter
access at the beginning of thehosts.allow
file before your default configuration statements. This should be benign, but it does have the effect of circumventing your strict TCP wrapper rules and you should be aware of this. If you don't like this semantic, you can modify therebuild-hosts.allow.sh
file to suit your preferences.The
tperimeter.py
file is written to require full IP quads when requesting access. For example, although TCP wrappers allow entries like64.23.
to specify a range of addresses, you cannot enter such an IP specification via thetperimeter
web interface. You also cannot specify the host from which you desire access by using its name, only its full IP quad address.When initially logging into the
tperimeter
interface, the user probably does not know their "real" dynamic IP address - i.e., The address they need opened bytperimeter
for the desired access. The dynamic IP addressing systems found in hotels, airports, and self-service kiosks vary considerably in their use ofNAT
and other address translation schemes.There is a trivial solution to this problem, however. Each time you log into the
tperimeter
system, simply submit the request without the service or address fields filled in.tperimeter
will automatically generate a request for ssh access at the current address through which you're connecting. (It determines the address from the http headers which is almost always the correct address to use.) This makes it simple to just hitEnter
at thetperimeter
entry screen and have the right thing happen.
tperimeter
.Any system that permits remote changes to the security environment of a server has the inherent risk that it can be compromised. The key to minimizing such exposure is careful customization, integration, and testing. TundraWare Inc. makes no claims that this software will work without security risks or compromise. The software is EXPERIMENTAL and is provided AS-IS. It is up to you to take the necessary steps to ensure this system is appropriate for your environment.
There are several areas you should take particular care to audit to ensure
your system security isn't going to get clobbered by tperimeter
:
- The web page the user accesses to make
tperimeter
requests should be both encrypted (SSL/hhtps) and be password protected. You have to make a policy decision whether to offer all authorized users the sametperimeter
login name and password or give them each their own individual login credentials. Either way, it's a good idea to watch the system log fortperimeter
requests to see how often and from where requests are showing up.- If you customize the programs, make sure you've not introduced coding errors that might cause it to cobble up your
/etc/hosts.allow
file.- Similarly take great care to construct the file tree that describes your desired default environment carefully.
- Make sure that file and directory permissions are correct. The requestor components (
tperimiter-ui.html
andtperimeter.py
) should be owned by the web daemon user (usuallywww
) and have permissions of 740 or even 700.rebuild-hosts.allow.sh
should be owned by root, again with permissions of 740 or 700.- It is common for dhcp-served users to exist behind a NATing firewall. That is, the dynamic IP address they are assigned is commonly non-routable and is NATed via public routable IP. This means that when they request access via
tperimeter
they are providing the public IP address that is serving many NATed users. In effect, the access control "hole"tperimeter
is opening will be available to everyone behind that NATed IP. This is whytperimeter
only offers a brief window of connection for requested services. It always "snaps back" to the system defaults for access.
tperimeter
requires a fairly current version of the python
programming language.
tperimeter
was developed and minimally tested on FreeBSD 4.x. and
apache 1.3. It should work without modification (other than the
customizations noted above) on other FreeBSD, Linux, and Apple OS/X
systems, but has not been tested at all in these environments.
tperimeter
is Copyright(c) 2006-2012 TundraWare Inc. For terms of
use, see the tperimeter-license.txt
file in the program
distribution.
Tim Daneliuk
tperimeter@tundraware.com
$Id: tperimeter.rst,v 1.5 2012/06/09 21:28:13 tundra Exp $
You can find the latest version of this program at:
http://www.tundraware.com/Software/tperimeter