Chapter 10. Securing network connections: Creating a VPN or DMZ

This chapter covers

  • Implementing server security configurations
  • Deploying an OpenVPN tunnel to secure remote connections
  • Using firewalls to control access between segments
  • Using iptables and Shorewall to create a DMZ-based network
  • Testing network connectivity solutions using virtual environments

They tell us we live in a hyper-mobile world. Not that I’d know: I rarely leave my home office. I get to enjoy the comforts of my home office because all the server resources I could possibly need are available remotely. Apparently I’m not alone.

Almost everyone whose work touches IT will access their professional tools from remote locations from time to time. And given that the public networks through which you access those remote locations are by their very nature insecure, you’re going to want to carefully control those connections.

The previous chapter focused on making sure that the data consumed by your remote clients is reliably transferred and invisible to anyone who might be lurking on the connecting network. This chapter, by sharp contrast, will focus on making sure that the data consumed by your remote clients is reliably transferred and invisible to anyone who might be lurking on the connecting network. See the difference? Neither do I.

In fact, there are all kinds of technologies devoted to securing network communication, and the principle of defense in depth teaches us never to rely on one. Here’s where you’ll learn about adding new layers of protection for your remote activities.

In this chapter, you’ll revisit a couple of old friends. You’ll use VirtualBox VMs and encryption to build a virtual private network (VPN) tunnel to permit secure and invisible remote connections. And, in a separate project, you’ll design more sophisticated firewall architectures to strategically divide your network into isolated segments. Finally, you’ll build a virtual network environment within VirtualBox so you can test your configurations.

10.1. Building an OpenVPN tunnel

I’ve talked a lot about encryption already in this book. SSH and SCP can protect data transferred through remote connections (chapter 3), file encryption can protect data at rest (chapter 8), and TLS/SSL certificates can protect data in transit between websites and client browsers (chapter 9). But sometimes your requirements demand protection across a broader range of connections because, occasionally, you’ve got different kinds of work to do. For instance, perhaps some members of your team need to work from the road using public WiFi hotspots. It’s definitely not smart to assume that random WiFi access points are secure, but your people do need a way to connect with company resources—VPNs to the rescue.

A properly designed VPN tunnel provides a direct connection between remote clients and a server in a way that hides data as it’s transferred across an insecure network. But so what? You’ve already seen lots of tools that can do that using encryption. The real value of a VPN is that once you’ve opened a tunnel, it’s possible to connect remote networks as though they’re all together locally. In a way, you’re circumventing that dodgy coffee shop hot spot.

Using such an extended network, admins can get their work done on their servers no matter where they might happen to be. But more importantly, as you can see in figure 10.1, a company with resources spread through multiple branch offices can make them all both visible and accessible to all the teams who need them, wherever they are.

Figure 10.1. Tunnel connecting remote private connections through a public network

The mere existence of a tunnel alone doesn’t guarantee security. But one of a number of encryption standards can be incorporated into the design, making things a great deal better. Tunnels built with the open source OpenVPN package use the same TLS/SSL encryption you’ve already seen in use elsewhere. OpenVPN is not the only available choice for tunneling, but it’s among the best known. And it’s widely assumed to be a bit faster and more secure than the alternative Layer 2 Tunnel Protocol using IPsec encryption.

You’ll want your team to safely connect with each other from out on the road or between multiple campuses. For that, you’ll need to build an OpenVPN server to permit sharing applications and to access the server’s local network environment. To make it work, it should be sufficient to fire up two VMs or containers: one to play the role of a server/host and the other of the client. Building a VPN involves quite a few steps, so taking a few moments to think about the big picture of how this is going to work will probably be worthwhile.

10.1.1. Configuring an OpenVPN server

Before getting started, here’s a helpful tip. If you’re going to follow along with this process on your own, and I strongly recommend that you do, you’ll probably find yourself working with multiple terminal windows open on your desktop, each logged in to a different machine. Take it from me, at some point you’re going to enter a command into the wrong window and totally mess up your environment. To avoid this, you can use the hostname command to change the machine name displayed on the command line to something that will visually remind you where you are. Once that’s done, you’ll need to exit the server and log back in again for the new setting to take effect. Here’s what it looks like:

ubuntu@ubuntu:~# hostname OpenVPN-Server
ubuntu@ubuntu:~$ exit                         1
<Host Workstation>$ ssh [email protected]
ubuntu@OpenVPN-Server:~#

  • 1 Activate your new hostname by exiting the shell and logging back in.

Following that approach to assign appropriate names to each of the machines you’re working with should help you keep track of where you are.

Note

After using hostname, you might encounter annoying Unable to Resolve Host OpenVPN-Server messages when running subsequent commands. Updating the /etc/hosts file to match the new hostname should solve that.

Preparing your server for OpenVPN

Installing OpenVPN on your server requires two packages: openvpn and, to manage the encryption key-generation process, easy-rsa. CentOS users should, if necessary, first install the epel-release repository the way you did back in chapter 2. To give you an easy way to test access to a server application, you could also install the Apache web server (apache2 for Ubuntu and httpd on CentOS).

While you’re setting up your server, you might as well do it right and activate a firewall that blocks all ports besides 22 (SSH) and 1194 (the default OpenVPN port). This example illustrates the way that will work on Ubuntu’s ufw, but I’m sure you still remember CentOS’ firewalld from chapter 9:

# ufw enable
# ufw allow 22
# ufw allow 1194

To permit internal routing between network interfaces on the server, you’ll need to uncomment a single line (net.ipv4.ip_forward=1) in the /etc/sysctl.conf file. This allows remote clients to be redirected as needed once they’re connected. To load the new setting, run sysctl -p:

# nano /etc/sysctl.conf
# sysctl -p

The server environment is now all set up, but there’s still a ways to go before you’re ready to flip the switch. Here are the steps we’ll cover over the next pages of this chapter:

  1. Generate a set of public key infrastructure (PKI) encryption keys on the server using scripts that come with the easy-rsa package. Effectively, an OpenVPN server also acts as its own Certificate Authority (CA).
  2. Prepare matching keys for the client.
  3. Configure a server.conf file for the server.
  4. Configure your OpenVPN client.
  5. Test your VPN.
Generating encryption keys

For simplicity, you’re going to set up your key infrastructure on the same machine that’s running the OpenVPN server. Security best practices, however, will usually suggest that a separate CA server be used for production deployments. In any case, figure 10.2 illustrates the process of generating and distributing encryption key resources for use on OpenVPN.

Figure 10.2. The files that will be created by your PKI server and their distribution targets

When you installed OpenVPN, a /etc/openvpn/ directory was automatically created, but there isn’t a whole lot in it just yet. Both the openvpn and easy-rsa packages come with sample template files that you can use as a base for you configuration. To jump-start the certification process, copy the easy-rsa template directory from /usr/share/ to /etc/openvpn/ and then change to the easy-rsa/ directory:

# cp -r /usr/share/easy-rsa/ /etc/openvpn
$ cd /etc/openvpn/easy-rsa

Because the easy-rsa directory will now contain quite a few scripts, table 10.1 gives you a quick preview of the tools you’ll be using to bring your keys into existence.

Table 10.1. Key easy-rsa scripts and their functions

Script name

Function

clean-all Removes old key files to prepare for new key generation
pkitool Frontend for OpenSSL (does most of the key-gen heavy lifting)
build-ca Uses the pkitool script to generate a root certificate
build-key-server server Uses the pkitool script to generate a key pair and certificate
build-dh Sets Diffie-Hellman authentication parameters
Note

These operations require root authority, so through sudo su, you’ll need to become root.

The first file you’ll work with is called vars, which contains environment variables that easy-rsa uses when it generates its keys. You’ll want to edit the file to substitute your own values for the sample defaults that are already there. Here’s what my file would look like.

Listing 10.1. Key excerpts from the /etc/openvpn/easy-rsa/vars file
export KEY_COUNTRY="CA"
export KEY_PROVINCE="ON"
export KEY_CITY="Toronto"
export KEY_ORG="Bootstrap IT"
export KEY_EMAIL="[email protected]"
export KEY_OU="IT"

Running the vars file will pass its values to the shell environment from where they’ll be incorporated into the contents of your new keys. Why would sudo alone not work? Because the first step edits a script called vars and then sources it. Sourcing means that the vars file passes its values to the shell environment from where those will be incorporated into the contents of your new keys.

Make sure to run the file again using a new shell if you need to complete an unfinished process. When that’s done, the script will encourage you to run the clean-all script to delete any existing content in the /etc/openvpn/easy-rsa/keys/ directory:

$ cd /etc/openvpn/easy-rsa/
# . ./vars                              1
NOTE: If you run ./clean-all,
  I will be doing a rm -rf on /etc/openvpn/easy-rsa/keys

  • 1 This command requires sudo permissions.

Naturally, your next step will be to run that clean-all script followed by build-ca, which uses the pkitool script to create your root certificate. You’ll be asked to confirm the identification settings provided by vars:

# ./clean-all
# ./build-ca
Generating a 2048 bit RSA private key

Next is the build-key-server script. Because it uses the same pkitool script along with the new root certificate, you’ll be asked the same confirmation questions to generate a key pair. The keys will be given names based on the arguments you pass, which, unless you’re running multiple VPNs on this machine, will normally be server as in this example:

# ./build-key-server server
[...]
Certificate is to be certified until Aug 15 23:52:34 2027 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

OpenVPN uses parameters generated using the Diffie-Hellman algorithm (by running build-dh) to negotiate authentication for new connections. The file that’s created here doesn’t need to remain secret, but it must have been generated using the build-dh script against the RSA keys that are currently active. If you create new RSA keys at some time in the future, you’ll also need to update the Diffie-Hellman file:

# ./build-dh

Your server-side keys will now have been written to the /etc/openvpn/easy-rsa/keys/ directory, but OpenVPN doesn’t know that. By default, OpenVPN will look for them in /etc/openvpn/, so copy them over:

# cp /etc/openvpn/easy-rsa/keys/server* /etc/openvpn
# cp /etc/openvpn/easy-rsa/keys/dh2048.pem /etc/openvpn
# cp /etc/openvpn/easy-rsa/keys/ca.crt /etc/openvpn
Preparing client encryption keys

As you’ve already seen, TLS encryption uses matching key pairs: one installed on the server and the other on a remote client. That means you’re going to need client keys. Our old friend pkitool is just the thing to cook some up. This example, run while still in the /etc/openvpn/easy-rsa/ directory, passes client as an argument to generate files called client.crt and client.key:

# ./pkitool client

The two client files, along with the original ca.crt file that’s still in the keys/ directory, will now have to be securely transferred to your client. Because of their ownership and permissions, this might be a bit complicated. The simplest approach is to manually copy the contents of the source file (and nothing but those contents) in a terminal running on your PC’s desktop (by highlighting the text, right-clicking over it, and selecting Copy from the menu), then pasting it into a new file of the same name you create in a second terminal logged in to your client.

But anyone can cut and paste. Instead, think like an admin, because you won’t always have access to a GUI where cutting and pasting is possible. Instead, copy the files to your user’s home directory (so a remote scp operation can access them) and then use chown to change the ownership of the files from root to your regular, non-root user so that remote scp action can work. Make sure your files are all settled in and comfy for now. You’ll move them over to the client a bit later:

# cp /etc/openvpn/easy-rsa/keys/client.key /home/ubuntu/
# cp /etc/openvpn/easy-rsa/keys/ca.crt /home/ubuntu/
# cp /etc/openvpn/easy-rsa/keys/client.crt /home/ubuntu/
# chown ubuntu:ubuntu /home/ubuntu/client.key
# chown ubuntu:ubuntu /home/ubuntu/client.crt
# chown ubuntu:ubuntu /home/ubuntu/ca.crt

With a full set of encryption keys ready for action, you’ll need to tell your server how you want to build your VPN. That’s done using the server.conf file.

Saving keystrokes

Too much typing for your poor, tired fingers? Brace expansion can help reduce those six commands to two. I’m sure you’ll be able to study these two examples and figure out what’s going on. More importantly, you’ll be able to figure out how to apply the principles to operations involving dozens or even hundreds of elements:

# cp /etc/openvpn/easy-rsa/keys/{ca.crt,client.{key,crt}} /home/ubuntu/
# chown ubuntu:ubuntu /home/ubuntu/{ca.crt,client.{key,crt}}
Configuring the server.conf file

How are you supposed to know what the server.conf file should look like? Well, remember the easy-rsa directory template you copied from /usr/share/? There are more goodies where that came from. The OpenVPN installation left a compressed template configuration file that you can copy to /etc/openvpn/. I’ll use the fact that the template is compressed to introduce you to a useful tool: zcat.

You already know about printing a file’s text contents to the screen with cat, but what if the file is compressed using gzip? You could always decompress the file, and cat will then be happy to print it, but that’s one or two steps too many. Instead, as you’ve probably already guessed, you can use zcat to load the decompressed text into memory all in one step. In this case, rather than print it to the screen, you’ll redirect the text to a new file called server.conf:

# zcat 
 /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz 
 > /etc/openvpn/server.conf
$ cd /etc/openvpn

Leaving out the extensive and helpful documentation that comes with the file, here’s how it might look once you’re done editing. Note that a semicolon (;) tells OpenVPN not to read and execute the line that follows.

Listing 10.2. The active settings from a /etc/openvpn/server.conf file
port 1194
# TCP or UDP server?
proto tcp
;proto udp
;dev tap
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 10.0.3.0 255.255.255.0"
keepalive 10 120
comp-lzo
port-share localhost 80
user nobody                      1
group nogroup
persist-key
persist-tun
status openvpn-status.log
log openvpn.log                  2
;log-append  openvpn.log
verb 3                           3

  • 1 Minimizes privileged system exposure
  • 2 Writes session logs to /etc/openvpn/openvpn.log
  • 3 Outputs verbosity, which can go as high as 9

Let’s work through some of those settings, one at a time:

  • By default, OpenVPN works over port 1194. You can change that, perhaps to further obscure your activities or avoid conflicts with other active tunnels. Because it requires the least coordination between clients, 1194 is normally your best choice.
  • OpenVPN uses either the Transmission Control Protocol (TCP) or User Datagram Protocol (UDP) for data transmissions. TCP might be a little bit slower, but it’s more reliable and more likely to get along with applications running at either end of the tunnel.
  • You can specify dev tun when you want to create a simpler and more efficient IP tunnel that transfers data content and nothing much else. If, on the other hand, you’ll need to connect multiple network interfaces (and the networks they represent) by creating an ethernet bridge, then you’ll have to select dev tap. If you haven’t a clue what all that means, go with tun.
  • The next four lines pass OpenVPN the names of the three server authentication files and the dh2048 parameters file you created earlier.
  • The server line sets the subnet range and netmask that’ll be used for assigning IP addresses to clients when they log in.
  • The optional push "route 10.0.3.0 255.255.255.0" setting allows remote clients to access private subnets behind the server. Making this work also requires network configuration on the server itself to ensure that the private subnet is aware of the OpenVPN subnet (10.8.0.0).
  • The line port-share localhost 80 allows client traffic coming in on port 1194 to be rerouted to a local web server listening on port 80. (This will be useful in this case because you’re going to use a web server to test your VPN.) This only works when proto is set to tcp.
  • The user nobody and group nogroup lines should be enabled by removing the semicolons (;). Forcing remote clients to work as nobody and nogroup ensures that their sessions on the server will be unprivileged.
  • log sets current log entries to overwrite old entries every time OpenVPN starts, whereas log-append appends new entries to the existing log file. The openvpn.log itself is be written to the /etc/openvpn/ directory.

In addition, it’s also common to add client-to-client to the config file so multiple clients will be able to see each other in addition to the OpenVPN server. Once you’re satisfied with your configuration, you’re ready to fire up the OpenVPN server:

# systemctl start openvpn
Note

Due to the evolving nature of the relationship between OpenVPN and systemd, starting the service might sometimes require a syntax like this: systemctl start openvpn@server.

Running ip addr to list your server’s network interfaces should now include a reference to a new interface called tun0. This will have been created by OpenVPN for the use of incoming clients:

$ ip addr
[...]
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc [...]
    link/none
    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever

It’s possible that you’ll need to reboot the server before everything will fully function. Next stop: the client computer.

10.1.2. Configuring an OpenVPN client

Traditionally, tunnels are built with at least two ends (otherwise we’d call them caves). Having OpenVPN properly configured on the server directs traffic into and out of the tunnel at that end. But you’ll need some kind of software running on the client side as well.

In this section, I’m going to focus on manually configuring a Linux computer of one sort or another to act as an OpenVPN client. But that’s not the only way you might want to consume the service. OpenVPN itself maintains client applications that can be installed and used on Windows or Mac desktop and laptops, or Android and iOS smartphones and tablets. See the https://openvpn.net website for details.

The OpenVPN package will need to be installed on the client machine as it was on the server, although there’s no need for easy-rsa over here because the keys you’ll use already exist. You’ll need to copy the client.conf template file over to the /etc/openvpn/ directory that the installation just created. This time, for some reason, the file won’t be compressed, so a regular cp will do the job just fine:

# apt install openvpn
# cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf 
 /etc/openvpn/

Most of the settings in your client.conf file will be fairly obvious: they’ll need to match the values used by the server. As you can see from the next sample file, one setting that’s unique is remote 192.168.1.23 1194, which points the client to the server’s IP address. Again, make sure you use your server’s address. You should also force your client to verify the authenticity of the server certificate to prevent a possible man-in-the-middle attack. One way to do this is by adding the remote-cert-tls server line.

Listing 10.3. The active settings in a VPN client’s /etc/openvpn/client.conf file
client                          1
;dev tap
dev tun
proto tcp
remote 192.168.1.23 1194        2
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
comp-lzo
verb 3
remote-cert-tls server          3

  • 1 Identifies the computer as a VPN client whose configuration will be based on a remote server
  • 2 The address and network port used to access the VPN server
  • 3 Enforces server certificate verification

Now you can move to the /etc/openvpn/ directory and pull those certification keys from the server. Substitute your server’s IP address or domain name for the one in the example:

$ cd /etc/openvpn
# scp [email protected]:/home/ubuntu/ca.crt .            1
# scp [email protected]:/home/ubuntu/client.crt .
# scp [email protected]:/home/ubuntu/client.key .

  • 1 The dot (.) at the end tells scp to save the file to the current directory.

Nothing exciting is likely to happen until you start OpenVPN on the client. Because you’ll need to pass a couple of arguments, you’ll pull the trigger from the command line. The argument --tls-client tells OpenVPN that you’ll be acting as a client and connecting via TLS encryption, and --config points to your config file:

# openvpn --tls-client --config /etc/openvpn/client.conf

Read the command output carefully to make sure you’re connected properly. If something does go wrong the first time, it’s probably due to a setting mismatch between the server and client configuration files or perhaps a network connectivity/ firewall issue. Here are some troubleshooting steps:

  • Carefully read the output from the OpenVPN operation on the client. It will often contain valuable hints to exactly what it couldn’t do and why.
  • Check for error-related messages in the openvpn.log and openvpn-status.log files in the /etc/openvpn/ directory on the server.
  • Check OpenVPN-related and timely messages in the system logs on both the server and client. (journalctl -ce will print out a screen full of the most recent entries.)
  • Confirm that you’ve got an active network connection between the server and client (see chapter 14 for details).

10.1.3. Testing your VPN

If everything OpenVPN spat out at you as it loaded on the client looks fine, then you should move on to test your tunnel to confirm that it’s working and protecting your connection. Running curl from the client against the server address using the OpenVPN port should return the index.html file in your web root directory (/var/www/html/):

curl 192.168.1.23:1194

Test your setup by removing the port number and the colon preceding it. Assuming your firewall is running with the previous settings, curl shouldn’t work.

The truth is, that alone is not a useful test. After all, the goal of a VPN is to prevent your session activity from being visible to other people on the network, so being able to load the page proves nothing. Without going into that much detail, the following sections suggest a couple of ways (in no specific order) to confirm that your VPN is working properly.

Network sniffing

Set up a regular GUI desktop PC as a client, and use your browser to open a server-based application that will require some kind of data entry. For the application, you could use a simple HTML form like the following.

Listing 10.4. A simple HTML page providing a browser data-entry form
<!DOCTYPE html>
<html>
<body>
<form action="/action_page.php">
  First name:<br>
  <input type="text" name="firstname" value="Your">
  <br>
  Last name:<br>
  <input type="text" name="lastname" value="Name">
  <br><br>
  <input type="submit" value="Submit">
</form>
</body>
</html>

You could save the file to the server’s web document root as, say, form.html. You’ll then access the page using the 192.168.1.23/form.html URL (substituting your server’s IP address).

To find out if the information you typed into the form would have been visible to unauthorized eyes, you can use network packet-sniffing software like Wireshark to capture and analyze the data. If the tunnel worked to encrypt the session, then the packets containing the names you entered would be unintelligible.

Unfortunately, a useful guide to setting up and using Wireshark for this purpose would require its own complete chapter. As that would be a significant detour away from our beloved Linux, that chapter will have to find a spot within a different book.

Network infrastructure

A second approach to testing your VPN involves setting up resources (servers, routers, and so on) within the server’s local network, the one to which you pushed clients from your server.conf file. Building infrastructure of one kind or another to make this work can get quite involved. But if you pull it off, and your client can access those resources, then you’ll know things are working. I’ve added a guide to using VirtualBox to build such an infrastructure at the end of this chapter.

10.2. Building intrusion-resistant networks

VPNs, through the magic of encryption, are great for protecting session data. And firewalls can nicely control incoming and outgoing traffic by port, protocol, or routing information. In theory, that should be enough to protect your server networks. After all, if you’ve locked down all but a couple of approaches into your network and strengthened the locks to the few doors that are still there (using, for instance, passwordless key-pair authentication for SSH), then you should be safe, right? If only it were that simple.

No matter how good you are, there’s no such thing as 100% when it comes to IT security. You do your best to keep informed about new kinds of threats, patch your software, audit your processes, and fine-tune your firewall, but someone’s always going to find a way through the wall. Besides the risk of human error and buggy or intentionally compromised software, it’s only a matter of time before (quantum computing?) machines capable of cracking encryption algorithms become widely available.

Practically, the solution is to over-provision by adding as many layers to your security profile as possible so that even if the bad guys make it past one gate, there should still be two or three others standing between you and the abyss. (Earlier, we called this defense in depth.) After thinking things through, you may decide that one of those layers involves separating your resources into multiple isolated networks in the hope that if one is breached, the others might still be protected.

When everything is said and done, the primary goal is to safely expose all the services that should be exposed and to jealously protect everything else. Let’s say you’re running a web server hosting a publicly available application. Users’ browsers will load their pages from the web server, while user information and application data are handled by a second server running a database. You’ll want to give everyone on earth (along with anyone who might be enjoying the view in low earth orbit) access to your web server, but close off all public access to the database server. Let’s discuss how that particular magic trick is done.

10.2.1. Demilitarized zones (DMZs)

One popular isolation architecture is known as a DMZ (a contraction of the phrase used to describe a geographic buffer between two distrustful nations: demilitarized zone). The idea is to divide your servers, workstations, WiFi routers, and other resources into separate networks. To make it work, each of your devices will need to be physically connected to a separate network interface.

One simple implementation of a DMZ, as illustrated in figure 10.3, is to use a single server as a router to redirect traffic between the internet and two internal networks. One of the networks might contain backend databases or the workstations and laptops used in your office. This network will be heavily protected by tight access rules. The other network will enjoy fairly direct and easy access to the outside world and might include public-facing resources like web servers.

Figure 10.3. A simple three-interface DMZ architecture

Before moving on to building your own DMZ environments, you should at least be aware of a couple alternatives to the DMZ model. I’ll mention some in the following sections.

Resistant networks: design considerations

In addition to DMZs, which are reliable and flexible enough to be candidates for a wide range of use cases, there are other secure network configuration models that you might consider.

A jump server (sometimes referred to as a jumpbox or, perhaps, a bastion host) is a lightweight server open to the internet that’s given only one function: allow remote SSH clients to log in and then “jump” on to other servers running on the jump server’s private network. As shown in figure 10.4, the private servers on the network would have some kind of access controls configured to permit access to only remote logins coming from the jump server.

Figure 10.4. A typical jump-server architecture

Jump servers (by definition, representing a possible single point of failure and an extra layer of complexity) aren’t as popular as they once were. As mentioned in chapter 9, proprietary hardware solutions provided by companies like Juniper and Cisco can be used to manage connectivity and security for larger enterprise deployments. But the costs of such hardware and the significant learning curve you’ll need to overcome before you’ll be able to competently use it can sometimes outweigh the benefits.

None of those systems will necessarily make all that much sense for hybrid cloud solutions, where company infrastructure is hosted both locally and on remote cloud platforms. But the underlying tools and design concepts are always going to be useful.

Why use DMZs?

Next up, I’m going to discuss creating a DMZ using two widely used software firewall packages: iptables and Shorewall. Before I do, though, I should tell you that for all intents and purposes, they’re pretty much the same thing. Shorewall is a more user-friendly tool that does nothing more than manipulate iptables rules without you seeing it. Here are two reasons why I’d like you to see both those approaches:

  • Usually there are going to be narrow, practical considerations that inform your choice of tools in these things, so having more than one option out of the box gives you a nice head start.
  • Even if you do end up using a simpler solution, like Shorewall, it’s good to catch at least a quick glimpse of iptables in its natural habitat. That will help deepen your understanding of Linux firewalls in general.

Here we go. Warning: complex and involved topic ahead. Skip to the end of the chapter if you feel like it. Remember to head right back here the next time you’re asked to build this kind of infrastructure.

10.2.2. Using iptables

iptables is a tool for managing firewall rules on a Linux machine. iptables? But what about the ufw and firewalld command sets you learned about in the previous chapter? So, you don’t like choices? And would it spoil your day if I told you that there was a fourth tool out there called nftables?

OK, I’ll admit that the whole thing does smell a bit funny, so let me explain. It all starts with netfilter, which controls access to and from the network stack at the Linux kernel module level. For decades, the primary command-line tool for managing netfilter hooks was the iptables rule set.

Because the syntax needed to invoke those rules could come across as a bit arcane, various user-friendly implementations like ufw and firewalld were introduced as higher-level netfilter interpreters. ufw and firewalld are, however, primarily designed to solve the kinds of problems faced by standalone computers. Building full-sized network solutions will often require the extra muscle of iptables or, since 2014, its replacement, nftables (through the nft command-line tool).

iptables hasn’t gone anywhere and is still widely used. In fact, you should expect to run into iptables-protected networks in your work as an admin for many years to come. But nftables, by adding on to the classic netfilter tool set, has brought some important new functionality. Still, for the sake of simplicity, I’m going to use iptables to quickly show you how to handcraft a DMZ from the command line. When that’s done, we’ll move on to the somewhat more intuitive Shorewall implementation.

10.2.3. Creating a DMZ using iptables

iptables should be installed by default. To confirm that, you can run iptables -L to list all the current rules. If you haven’t been playing around with it yet, you should see a completely open (ACCEPT) firewall. Note that the INPUT, FORWARD, and OUTPUT chains are all part of the default Filter table. The NAT table that also exists by default can be used to alter (or translate) a packet’s routing information so it can move between networks successfully. We’ll revisit NAT a bit later:

# iptables -L
Chain INPUT (policy ACCEPT)                                  1
target     prot opt source     destination
ACCEPT     tcp  --  anywhere   anywhere     tcp dpt:domain
ACCEPT     udp  --  anywhere   anywhere     udp dpt:domain
ACCEPT     tcp  --  anywhere   anywhere     tcp dpt:bootps
ACCEPT     udp  --  anywhere   anywhere     udp dpt:bootps

Chain FORWARD (policy ACCEPT)
target     prot opt source     destination
ACCEPT     all  --  anywhere   anywhere
ACCEPT     all  --  anywhere   anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source     destination

  • 1 The output (part of the Filter table in this case) identifies rules by chain: INPUT in this first example.

Once you’ve got an overall plan, which in this case is separating the kinds of servers you’re running using a DMZ setup, you should set a strict default policy.

Tip

Firewall admin rule #1: always know how it’s supposed to end before you start.

These rules form the baseline of a firewall by blocking (DROP) all incoming and forwarding traffic for all interfaces, but allowing outgoing:

# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT ACCEPT

Because their internet connection comes through the router server (perhaps via a network switch), all of the devices on your networks are automatically bound to these rules. Test it out for yourself. Again, feel free to use the virtual network infrastructure described as follows. We’ll assume that the three network interfaces attached to your firewall server are named as described in table 10.2.

Table 10.2. Network interface designations used for the coming examples

Designation

Purpose

eth0 Connected to the internet
eth1 Connected to the DMZ
eth2 Connected to the local private network

Linux naming conventions for network interfaces

Once upon a time, you could have safely assumed that your Linux distro would assign simple and straightforward names for the physical network interfaces attached to your computer. The first ethernet interface recognized would be eth0, the second one, eth1, and so on; wireless interfaces would be wlan0 and wlan1 and so forth. (As you saw in chapter 9, virtual devices like tunnels and bridges can be given names using different conventions.) The point is that even if you didn’t happen to know an interface’s exact name, you could usually guess it pretty quickly. But run ip addr on your modern systemd machine, and you may come face to face with something like enp1s0. Or how about this abomination: wlx9cefd5fe4a18. Just trips off your tongue when you repeat it, no?

Here’s what’s going on. For many solid reasons, systems using predictable interface names are easier and safer to manage, even if there’s a bit of a convenience trade-off. An ethernet interface might be made up of en for ethernet, p1 to indicate bus 1, and s0 to indicate the first physical slot. And a different device might get wl (wireless LAN) and x9cefd5fe4a18, where the x indicates that the hexadecimal number that follows is the device’s MAC address.

As long as you know where a device is plugged in and/or what its MAC address is, you can safely predict its interface name. Nevertheless, for simplicity, I’ll use the older conventions for this chapter’s examples.

You’ll want the devices within your local network to be able to communicate with the public-facing servers, including the router itself, in the DMZ. These two rules added to the FORWARD chain in the Filter table will allow data packets to move (FORWARD) between the networks behind the eth1 and eth2 interfaces. -A indicates that what follows should be added as a new rule. This allows your web server in the DMZ to exchange data with the database server in the private network:

iptables -A FORWARD -i eth1 -o eth2 -m state 
 --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth2 -o eth1 -m state 
 --state ESTABLISHED,RELATED -j ACCEPT

This next rule will be added to the NAT table (-t nat). It uses the TCP protocol to handle all traffic coming through the eth0 interface that’s aimed at your application’s (fictional) public IP address (54.4.32.10) and specifies that it wants to use the HTTP port 80. Any traffic meeting all of those conditions will be rerouted to the internet IP address of your web server on the DMZ (192.168.1.20):

iptables -t nat -A PREROUTING -p tcp -i eth0 -d 54.4.32.10 
 --dport 80 -j DNAT --to-destination 192.168.1.20

Because you haven’t opened any access from the internet through the eth0 interface to either the DMZ or the private network, nothing coming from the outside can reach any local servers.

You may think you’re done, only you’re not. Wait a half hour or so, and you should start receiving angry emails from the developers on your team wondering why they can’t download critical software updates or cute cat videos. Be prepared to customize your firewall settings to accommodate unexpected special needs (like access to and from remote software repositories or cloud resources). Ideally, you should anticipate the things you’ll need before building the firewall, but the old “pull the trigger and see what breaks” approach also works.

As I mentioned before, iptables isn’t at the vanguard of firewalling technology any more, and this example was very bare-bones basic, but I think it does help illustrate how such things work. If you’re curious about how the big boys and girls get this kind of thing done on newer deployments, an official guide to putting together something similar using nftables is available at http://mng.bz/b0DM.

10.2.4. Creating a DMZ using Shorewall

I’m sure you already know the drill: the first step is to get the software. Ubuntu users can use APT to install the shorewall package, although those on CentOS will need to get it through the epel-release repository:

# yum install epel-release
# yum install shorewall

Unlike the command-line-based iptables, Shorewall is managed through configuration files. There’s something about having the solid visual representation of complex settings provided by config files that I personally find reassuring. Once you wrap your mind around the way Shorewall settings are spread across a half dozen or so files, you’ll probably find working with Shorewall syntax much less intimidating than iptables.

Shorewall startup options are controlled by the /etc/default/shorewall file, but the firewall configuration itself is normally handled by a number of files in the /etc/shorewall/ directory. /etc/shorewall/shorewall.conf sets the shell environment within which Shorewall will run. It’s possible that for simple projects, you won’t even need to touch either that file or the params and conntrack files that you’ll also find there. You will, however, need to create some other files for which templates exist in /usr/ share/doc/ shorewall/examples/ (or /usr/share/doc/shorewall-5.0.14.1/Samples on CentOS, where 5.0.x is the version number). If you list the contents of that examples/ directory, you’ll see four subdirectories that, in turn, contain sample configuration files covering a number of common scenarios:

# ls /usr/share/doc/shorewall/examples/
LICENSE.gz     README.txt        two-interfaces
one-interface  three-interfaces  Universal

Even though the three-interfaces option looks like a good match for what we’re planning here, we’ll put together what we need from scratch so you can see clearly and exactly how the process works. Table 10.3 shows a quick rundown of the /etc/shorewall/ files you might find yourself using.

Table 10.3. Shorewall configuration files kept in /etc/shorewall/

Filename

Purpose

Required

zones Declares the network zones you want to create Yes
interfaces Defines which network interfaces will be used for specified zones Yes
policy Defines high-level rules controlling traffic between zones Yes
rules Defines exceptions to the rules in the policy file No
masq Defines dynamic NAT settings No
stoppedrules Defines traffic flow while Shorewall is stopped No
params Sets shell variables for Shorewall No
conntrack Exempts specified traffic from Netfilter connection tracking No

There’s lots of good documentation available through man by invoking man shorewall-, along with the name of the particular file you’re looking for:

$ man shorewall-rules
The zones file

Let’s get started using a text editor to create a zones file. The first line defines the Shorewall server as type firewall. Each of the three active zones you’ll create will use type ipv4 addressing (as opposed to IPv6). The net zone represents the public network (the one all the cool kids call the internet), dmz will be the public-facing zone within your infrastructure, and loc will be the private, local network for your backend servers.

Listing 10.5. /etc/shorewall/zones
fw firewall
net ipv4
dmz ipv4
loc ipv4
The interfaces file

Now you’ll need to create a file called interfaces where you’ll associate each of your new zones with one of the three network interfaces you’ve got attached to the Shorewall server. detect tells Shorewall that you want the network settings to be automatically detected; dhcp means that you want IP addresses automatically assigned to your interfaces by DHCP servers. And nosmurfs,routefilter,logmartians on the internet-facing interface will filter suspicious packets and source domains, and log-related events.

Listing 10.6. /etc/shorewall/interfaces
net eth0 detect dhcp,nosmurfs,routefilter,logmartians           1
dmz eth1 detect dhcp
loc eth2 detect dhcp

  • 1 Maps the eth0 interface to the internet (net) zone and establishes behavior protocols
The policy file

The policy file establishes the default, baseline behavior you want. The first line in this example will silently delete all traffic coming from the internet (net) directed at any destination. Outbound traffic from the private zone (loc) to the internet is allowed, enabling local machines to receive software updates. The third line states that traffic originating from the firewall should be accepted everywhere. The final line rejects any packets not covered by other rules.

Listing 10.7. /etc/shorewall/policy
net all DROP              1
loc net ACCEPT
fw all ACCEPT
all all    REJECT         2

  • 1 DROP will delete filtered packets, but REJECT will delete and also send a notice to the sender.
  • 2 This policy must come last as it covers all traffic that isn’t covered by a preceding rule.
The rules file

The only other file you’ll need to create for this simple configuration is rules. A rules file can, as your needs change, become quite long and complex. For this exercise, however, you’ll need only a few lines. The primary goal of the rules file is to fine-tune the broad-strokes exclusions of the policy file.

For instance, because you’ll be running a web server in the DMZ zone, you’ll want to allow all traffic using the TCP protocol to access via either port 80 (insecure HTTP) or port 443 (secure HTTP). You’ll also want to open SSH access from your local servers to machines (including the Shorewall firewall server itself) in the DMZ. Without SSH, how will admin workstations on the local network be able to administer the firewall?

If necessary for remote SSH access, you might also open port 22 from the net network to the firewall. The Web(DNAT) rule allows port-forwarding access from the internet to your web server in the DMZ. Although it’s not a part of this chapter’s example, if you end up running a DNS server on your firewall machine, you’ll also open access for port 53 from your local network to the firewall machine.

Listing 10.8. /etc/shorewall/rules
ACCEPT all dmz tcp 80,443
ACCEPT net dmz tcp 22
ACCEPT loc dmz tcp 22
ACCEPT loc fw udp 53
Web(DNAT) net dmz:10.0.1.4

All that’s left is to start up Shorewall on the firewall machine:

# systemctl start shorewall
Note

Don’t forget to restart Shorewall after making edits to the configuration files. And don’t think you won’t be making edits to the configuration files as you struggle to get everything working the way it’s supposed to.

10.3. Building a virtual network for infrastructure testing

You know as well as I do that you have to try a tool out for yourself before you can understand how it works. But trying out the deployments discussed in this chapter will require more than one or two virtual servers to test. To do a proper job here, you’ll need to set up multiple networks whose I/O access can be fully controlled.

If you’ve got a few spare machines, some cabling, and a couple of switches lying around then, great, roll up your sleeves and have at it. I for one really miss playing with server and networking hardware. But what can I do? My world is pretty much all virtual now: I can’t even remember the last time I opened up my own workstation.

If, like me, you’re stuck with whatever networks you can build for yourself on a command line, here’s how it can work. You’re going to use VirtualBox to create a couple of virtual NAT networks, provision network interfaces for each of the VMs you’ll launch, and manually associate the interfaces with the appropriate networks.

Bear in mind that the number of VirtualBox VMs you’ll be able to launch is limited by the amount of free physical memory and CPU power you’ve got on your VirtualBox host machine. With a Linux host running on 8 GB of RAM, you might be able to squeeze out three concurrent VMs. And don’t even think about trying that on a Windows host unless you’ve got at least 16 GB of RAM. Consider offloading one or two VMs on to a separate PC within your network.

You’ll use the vboxmanage command-line tool for the first step (creating the networks for a DMZ configuration). As far as I can see, there’s no way to do this from within the VirtualBox GUI. The command natnetwork add tells VirtualBox that you want to add a new NAT network. In the first example, the netname will be dmz, and the subnet will be 10.0.1.0/24. The second network will be called loc (for local), and its subnet will be 10.0.2.0/24. When the networks are created, you’ll start them using natnetwork start:

$ vboxmanage natnetwork add --netname dmz 
 --network "10.0.1.0/24" --enable --dhcp on         1
$ vboxmanage natnetwork add --netname loc 
 --network "10.0.2.0/24" --enable --dhcp on
$ vboxmanage natnetwork start --netname dmz
$ vboxmanage natnetwork start --netname loc

  • 1 Because these are only virtual networks, creating them doesn’t require admin permissions.
Note

Due to a known bug, it might not be possible to create and run NAT networks on VirtualBox versions older than 5.1.

The next step is to create (or, better, clone) the VMs you’ll need. (Make sure you’ve got enough system memory and CPU power on your host machine to handle all the VMs you plan to launch.) Before you start the VMs, click once on the first one’s name in the VirtualBox list, then click the Settings button, and then click the Network item on the left side. If this VM is going to be, say, a Shorewall server, then attach its first network adapter to whichever interface you normally use to give your VMs full internet access.

Now click the Adapter 2 tab and then the Attached To drop-down menu, and select the NAT Network setting. Because you’ve already created a couple of NAT networks, both should be available as options (figure 10.5). Select one of them for Adapter 2, and then the other for Adapter 3.

Figure 10.5. Associating a network adapter attached to a NAT network to a VirtualBox VM

To complete a Shorewall test environment, work through the Settings | Network section of your other two VMs and associate one with the dmz NAT network, and the other with loc. Those two VMs will have only one interface each.

With all that done, you can fire up your three VMs and log in. Run ip addr on each to confirm that the interfaces have been recognized and are connected to their networks. If you see the right kind of IP address on the inet line (like 10.0.1.5/24), then everything’s working:

$ ip addr
2: enp0s3:: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc [...]
    inet 10.0.1.5/24 brd 10.0.1.255/ scope global enp0s3              1
       valid_lft forever preferred_lft forever

  • 1 This interface is properly connected to your dmz NAT network.

But if there is no inet address, then you’ll need to bring it up manually. Take the interface name (enp0s3, in the example) and use it as an argument for ifconfig up. That tells the interface that it had better wake up and get to work. Running dhclient will then request an IP address on the dmz network from a DHCP server. (Remember how you set --dhcp on when you created the NAT network? That was for a reason.)

# ifconfig enp0s3 up
# dhclient enp0s3            1

  • 1 If this operation fails, there might be something wrong with your network hardware or configuration.

Finally, run ip addr once again to make sure everything is as it should be. You’ve got yourself a test environment. If you’re not sure you’re quite clear on subnetting and NAT networks, all is not lost: hang on until chapter 14.

Summary

  • VPN tunnels can be used to secure remote connections and also to safely expose network infrastructure between remote locations.
  • The Easy RSA package contains scripts that can be used to generate a full public key infrastructure (PKI) for TLS encryption applications.
  • Firewalls and network architecture can be used together to create protected subnet environments for resources that should not be exposed to public networks.
  • The Shorewall firewall tool is configured for varying levels of complexity through plain text files, whereas the iptables firewall implementation is controlled from the command line.
  • A DMZ network structure uses firewall configurations to place vulnerable resources in protected, private subnets and public-facing servers in subnets, allowing easier remote access.
  • iptables and nftables are deep and flexible command-line implementations of the netfilters Linux kernel firewall tool.

Key terms

  • A virtual private network (VPN) is a method for connecting remote networks and safely exposing resources between them.
  • A VPN tunnel describes the way network protocols can be used to obscure VPN traffic as it moves across insecure networks.
  • A VPN client is a device logging in to or through a VPN server. In the case of OpenVPN, the client could be a smartphone or PC running the OpenVPN GUI client application, or a Linux machine configured using OpenVPN.
  • A packet sniffer like WireShark can capture and analyze data packets as they move through a network, revealing details about their content, origin, and destination.
  • A NAT network presents a single external IP address to a public network while managing traffic to and from private devices behind it. This will be discussed in much greater detail in chapter 14.

Command-line review

  • hostname OpenVPN-Server sets the command prompt description to make it easier to keep track of which server you’re logged in to.
  • cp -r /usr/share/easy-rsa/ /etc/openvpn copies the Easy RSA scripts and environment configuration files to the working OpenVPN directory.
  • ./build-key-server server generates an RSA key pair set with the name server.
  • ./pkitool client generates a client set of keys from an existing RSA key infrastructure.
  • openvpn --tls-client --config /etc/openvpn/client.conf launches OpenVPN on a Linux client using the settings from the client.conf file.
  • iptables -A FORWARD -i eth1 -o eth2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT allows data transfers between the eth1 and eth2 network interfaces.
  • man shorewall-rules displays documentation on the rules file used by Shorewall.
  • systemctl start shorewall starts the Shorewall firewall tool.
  • vboxmanage natnetwork add --netname dmz --network "10.0.1.0/24" --enable --dhcp on uses the VirtualBox CLI to create and configure a virtual NAT network with DHCP for VirtualBox VMs.
  • vboxmanage natnetwork start --netname dmz starts a virtual NAT network.
  • dhclient enp0s3 requests an IP address for the enp0s3 interface from a DHCP server.

Test yourself

1

A properly configured OpenVPN tunnel can improve security by

  1. Applying firewall rules to control access between networks
  2. Isolating network-attached devices through subnetting
  3. Adding encryption to network connections
  4. Obscuring traffic moving through a public network

2

To enable internal routing on a server, you need to uncomment a line in the /etc/sysctl.conf file. Which one?

  1. net.ipv4.ip_forward=1
  2. net.ipv4.tcp_syncookies=1
  3. net.ipv6.conf.all.accept_redirects = 0
  4. net.ipv4.conf.all.accept_source_route = 0

3

After installing easy-rsa, where will you find the scripts you’ll use to generate your keys?

  1. /usr/share/easy-rsa/
  2. /usr/share/easy-rsa/scripts/
  3. /usr/share/easy-rsa/examples/
  4. /usr/share/docs/easy-rsa/

4

Which of the following scripts will do most of the work generating RSA scripts?

  1. vars
  2. build-key-server
  3. build.ca
  4. pkitool

5

After installing OpenVPN, where will you find configuration file templates?

  1. /usr/share/doc/openvpn/examples/sample-config-files/server.conf/
  2. /usr/share/doc/openvpn/sample-config-files/server.conf.gz
  3. /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz
  4. /usr/share/openvpn/examples/sample-config-files/server/

6

Which of the following values can be added to the /etc/openvpn/server.conf file to port-forward clients to a web server?

  1. port-share localhost 80
  2. proto tcp
  3. client-to-client
  4. push "route 10.0.3.0 255.255.255.0"

7

Which of the following iptables commands will silently block all traffic sent to an interface?

  1. iptables -P OUTPUT DROP
  2. iptables -P INPUT DROP
  3. iptables -P INPUT REJECT
  4. iptables -P FORWARD DROP

8

Which of the following Shorewall files is used to set a default access profile for your firewall?

  1. params
  2. interfaces
  3. rules
  4. policy

Answer key

1.

c

2.

a

3.

a

4.

d

5.

c

6.

a

7.

b

8.

d

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.117.4