Software-Based Routing with VyOS

PR-825-1-3

A modern business’ stability and efficiency depend largely on the continuous operation of its IT infrastructure. Unfortunately, maintenance and operating expenses can be quite high, especially for small and medium-sized businesses.

To cut costs, many companies are now looking to IT outsourcing: instead of purchasing their own equipment, companies rent from a data center and hire professionals to maintain it.
For this to be beneficial from an organizational and financial standpoint, the technical side of things needs to be thoroughly thought out.

When transferring part of an IT infrastructure to a data center, it’s important to decide how all of the resources will connect to a single network. Solutions offered by the leading manufacturers (Juniper, Cisco, etc.) are often too pricey for small and medium-sized businesses. Keeping this in mind, it’s no surprise that there has been a growing interest in free open-source products. In terms of functionality, most of these work the same as their for-pay counterparts, if not better.

A key member of the corporate network is the router–a special network device that connects network elements together and exchanges packets between them. Routers can be both hardware and software-based. When trying to build an IT infrastructure while minimizing expenditures, a software-based router may be the best option.

In this article, we’ll be looking at the VyOS router, which is distributed under free license, and how it can be used to solve some real-life tasks.

VyOS: General Information

VyOS is a fork of the now defunct Vyatta network OS (now owned by Brocade). It was first released in December 2013 under the codename Hydrogen.

Its latest major release, Helium, was published in September 2014. The VyOS command line interface (CLI) is similar to the CLI for Juniper Networks devices.

VyOS has many different features, including:

  • IPv4 and IPv6 firewalls with p2p traffic filtering;
  • network address translation (NAT);
  • IPv4 and IPv6 DHCP servers;
  • an intrusion detection system;
  • load balancing and backup channels;
  • secondary routing with connection status table synchronization;
  • VPN (IPsec, L2TP/IPsec, PPTP, OpenVPN);
  • traffic analysis (NetFlow and sFlow);
  • web proxy and URL filtering.

Like Vyatta, VyOS is built on Debian. This lets us add functions by installing additional deb packages.

Installation

For detailed instructions, look here. VyOS has two installation methods: install system and install image. The first option (install system) just installs the operating system onto a disk. When you choose install image, every version of VyOS gets saved to a separate directory, letting you rollback to a previous version if any issues arise (this is the recommended installation method).

So, we boot from our disk, log into the system (login – vyos, password – vyos), and run the install image command. During the installation, we’ll need to answer the standard Linux installation questions. Once the installation is complete, we run reboot, and again start up the system and log onto VyOS with the login and password we set during installation.

Practical Example

We’ll look at VyOS’ features by running some practical examples. The scenario: an organization is made up of three geographically distributed branches: one in Moscow, one in St. Petersburg, and the third in Habarovsk. They have four servers in a data center in St. Petersburg. Our task: allow only one server to connect directly to the Internet; the others should be connected to a local network and access the Internet through the router. Each of our branches will be using a different connection type: L2TP/IPsec, PPTP, and OpenVPN.

Our network will look like this:

pic-7

Configuring Nodes

Even though we’ve already installed VyOS, we still don’t have a network, so we’ll start by configuring one in the KVM console.

We configure the first network interface (external) to have the address 95.213.170.75. Then, we enter configuration mode by entering the command configure.

set interfaces ethernet eth0 address 95.213.170.75/29
set interfaces ethernet eth0 description "WAN"

Here, we’ve assigned interface eth0 an IP address and a description to avoid confusion later on.

Then we set the default gateway address and DNS address:

set system gateway-address 95.213.170.73
set system name-server 188.93.16.19

We’ve entered the address for the Selectel DNS in St. Petersburg, but any will do.
Next, we configure our SSH service, which we’ll later use for configuring future nodes:

set service ssh port "22"

The logic behind VyOS is almost the same as with Juniper Networks devices: before any changes come into effect, the commit command has to be executed. For changes to stay in effect after rebooting, we have to run the save command. This is where the VyOS command logic differs from JunOS: in Juniper’s network OS, changes don’t have to be saved after running commit.

We connect to our router via SSH then log onto the system by entering the login and password we set during installation. Once we’ve logged on, we configure the internal network interface eth1. This is the local network interface that the servers in the data center connect to. We assign it the address 10.0.10.1 with netmask /24 and add a description:

set interfaces ethernet eth1 address 10.0.10.1/24
set interfaces ethernet eth1 description "LAN"

If we want our machine to recognize network resource names, we have to configure the DNS. We can configure a DNS forwarder, which will forward requests to the name resolution assigned in the configuration. Configuring this component is fairly simple:

set service dns forwarding cache-size "0"
set service dns forwarding listen-on "eth1"
set service dns forwarding name-server "188.93.16.19"
set service dns forwarding name-server "188.93.17.19"

In the first command, we set the cache size of the DNS forwarder for saving records. Since there’s really no point for us to save any DNS records, we set this to zero. The second command sets the interface the DNS forwarder will listen on. We’ve entered an internal interface so that our DNS forwarder won’t be accessible to the whole Internet. The third and fourth commands establish which addresses requests will be forwarded to. Our example uses Selectel’s DNS, but again, you can set any servers you want.

All of the components we need for our local network are ready to go. Now we configure the firewall.

In VyOS, we can use firewall rulesets and assign them names. In our example, we use a set of rules called OUTSIDE for our external network and INSIDE for our internal network.

We want to permit all connections “from the inside out” for our external interface, and for our internal interface, all connections “from the inside out” and SSH access.

set firewall name OUTSIDE default-action "drop"
set firewall name OUTSIDE rule 1 action "accept"
set firewall name OUTSIDE rule 1 state established "enable"
set firewall name OUTSIDE rule 1 state related "enable"

These commands allow all pre-established and related connections.

Then we set the INSIDE firewall rules:

View Rules
set firewall name INSIDE default-action 'drop'
set firewall name INSIDE rule 1 action 'accept'
set firewall name INSIDE rule 1 state established 'enable'
set firewall name INSIDE rule 1 state related 'enable'
set firewall name INSIDE rule 2 action 'accept'
set firewall name INSIDE rule 2 icmp type-name 'echo-request'
set firewall name INSIDE rule 2 protocol 'icmp'
set firewall name INSIDE rule 2 state new 'enable'
set firewall name INSIDE rule 3 action 'drop'
set firewall name INSIDE rule 3 destination port '22'
set firewall name INSIDE rule 3 protocol 'tcp'
set firewall name INSIDE rule 3 recent count '4'
set firewall name INSIDE rule 3 recent time '60'
set firewall name INSIDE rule 3 state new 'enable'
set firewall name INSIDE rule 31 action 'accept'
set firewall name INSIDE rule 31 destination port '22'
set firewall name INSIDE rule 31 protocol 'tcp'
set firewall name INSIDE rule 31 state new 'enable'

In the first line, we assign the default action; here, it’s “drop” (the firewall will drop all packets that fall outside any of our rules). The first rule mimics the rules we wrote for the external interface. The second rule allows all ICMP packets; this is needed for pinging the router if anything goes wrong. The third rule is responsible for SSH connections: we’re only allowing TCP traffic from port 22.

Now we apply these new rules to the appropriate interfaces:

set interfaces ethernet eth0 firewall in name 'OUTSIDE'
set interfaces ethernet eth1 firewall out name 'INSIDE'

Take a look at the in and out parameters. These describe traffic relative to the router, either incoming or outgoing, and are in no way related to the names of the firewall rulesets.

We won’t forget to apply and save our configuration using the commit and save commands.

Configuring a VPN

As we’ve already said, our branches will be using different kinds of VPN connections. We’ll start by configuring L2TP/IPSec (for more information, see here):

set vpn ipsec ipsec-interfaces interface eth0
set vpn ipsec nat-traversal enable
set vpn ipsec nat-networks allowed-network 0.0.0.0/0

set vpn l2tp remote-access outside-address 95.213.170.75
set vpn l2tp remote-access client-ip-pool start 10.0.10.20
set vpn l2tp remote-access client-ip-pool stop 10.0.10.30
set vpn l2tp remote-access ipsec-settings authentication mode pre-shared-secret
set vpn l2tp remote-access ipsec-settings authentication pre-shared-secret 
set vpn l2tp remote-access authentication mode local
set vpn l2tp remote-access authentication local-users username  password 

In the first three commands we configure IPSec: we define the interface where packets will be sent, we enable NAT traversal, and allow NAT for all networks. The next commands are for L2TP. It’s fairly obvious what they’re responsible for, so we’ll just take a look at a few parameters:

    • outside-address: sets the VPN server’s external address;
    • pre-shared-secret: sets the password which will later be used when configuring the VPN on client devices;
    • authentication mode local: sets the authentication type. Our example uses a local database for authentication, but a RADIUS server can also be used for centrally managing user accounts.

In the last line, we create a user and define their password. Afterwards, we add some rules to the firewall to allow L2TP/IPSec traffic.

View Firewall Rules
set firewall name INSIDE rule 4 action 'accept'
set firewall name INSIDE rule 4 protocol 'esp'
set firewall name INSIDE rule 41 action 'accept'
set firewall name INSIDE rule 41 destination port '500'
set firewall name INSIDE rule 41 protocol 'udp'
set firewall name INSIDE rule 42 action 'accept'
set firewall name INSIDE rule 42 destination port '4500'
set firewall name INSIDE rule 42 protocol 'udp'
set firewall name INSIDE rule 43 action 'accept'
set firewall name INSIDE rule 43 destination port '1701'
set firewall name INSIDE rule 43 ipsec 'match-ipsec'
set firewall name INSIDE rule 43 protocol 'udp'

Rule 4 permits ESP traffic, which our installed IPSEC tunnel works on, 42 allows NAT traversal, and 43 enables port 1701, which L2TP works on.

Now let’s look at configuring our second VPN connection and set up an OpenVPN server. We start by copying the easy-rsa files to the directory /config/easy-rsa2 to avoid losing them when updating the system:

cp -rv /usr/share/doc/openvpn/examples/easy-rsa/2.0/ /config/easy-rsa2

If necessary, we can change the default variables for certificates. For example:

nano /config/easy-rsa2/vars

export KEY_COUNTRY="RU"
export KEY_CITY="Saint-Petersburg"
export KEY_ORG="Selectel"
export KEY_EMAIL="t-rex@selectel.ru"

This data will be displayed in the fields of certificates we generate. We jump to the /config/easy-rsa2/ directory and load the variables:

cd /config/easy-rsa2/
source ./vars

We delete all of the keys:

./clean-all

Then we generate the certificate authority files:

./build-ca
./build-dh

and the server certificate:

./build-key-server t-rex-server

Next, we copy the keys to the appropriate directories:

cp /config/easy-rsa2/keys/ca.crt /config/auth/
cp /config/easy-rsa2/keys/dh1024.pem /config/auth/
cp /config/easy-rsa2/keys/t-rex-server.key /config/auth/
cp /config/easy-rsa2/keys/t-rex-server.crt /config/auth/

Once we’ve done this, we prepare client files for connecting to the server:

./build-key branch-msk

and immediately copy them to a separate folder:

cd /config/easy-rsa2/keys
mkdir branch-msk
cp branch-msk* branch-msk/
cp ca.crt branch-msk/

The generated files are necessary for connecting clients to the server, which means they will have to be transferred to the client’s side. This can be done using any SCP client: WinSCP for Windows or the standard console client scp for Linux.

Then we configure the server:

set interfaces openvpn vtun0 mode 'server'
set interfaces openvpn vtun0 server name-server '10.0.10.1'
set interfaces openvpn vtun0 server push-route '10.0.10.0/24'
set interfaces openvpn vtun0 server subnet '10.1.10.0/24'
set interfaces openvpn vtun0 tls ca-cert-file '/config/auth/ca.crt'
set interfaces openvpn vtun0 tls cert-file '/config/auth/t-rex-server.crt'
set interfaces openvpn vtun0 tls dh-file '/config/auth/dh1024.pem'
set interfaces openvpn vtun0 tls key-file '/config/auth/t-rex-server.key'
set service dns forwarding listen-on vtun0

commit
save

Take a look at the last command: we forward name resolution requests to the DNS forwarder that we configured earlier. We’d also like to point out that with OpenVPN, we first used a separate network for building the actual tunnel, and then routed it to the local network with our servers. This is due to the nature of the protocol. We’ll write more detailed information on this in a future article.

Configuring a PPTP Server

Now we’ll configure the last of our VPN connections–PPTP. Of course, PPTP is not very secure and thus not often used for transferring confidential information; however, it has many applications for providing remote access. Practically every device with a network connection has a PPTP client.

From our example, we can see that PPTP is configured almost the same way as L2TP:

set vpn pptp remote-access authentication mode local
set vpn pptp remote-access authentication local-users username  password 
set vpn pptp remote-access client-ip-pool start 10.0.10.31
set vpn pptp remote-access client-ip-pool stop 10.0.10.40
set vpn pptp remote-access dns-server server-1 188.93.17.19
set vpn pptp remote-access outside-address 95.213.170.75

In the first command, we set user authentication mode to local. If you have a RADIUS server, you can choose radius authentication mode, which can be used to manage user accounts much more comfortably.

Then we create local users and set an IP address range and DNS data for clients. The last command sets the address of the interface our server will listen on.

Then we apply and save the configuration:
commit
save

The server is now ready for clients.

All that’s left is to let traffic from the local network out. This is how Internet access is provided to servers in the local network and to users connected to our router from the branches:

set nat source rule 1 outbound-interface 'eth0'
set nat source rule 1 source address '10.0.10.0/24'
set nat source rule 1 translation address masquerade

Conclusion

Now we’re ready: we’ve built a network to accomplish our task with the given conditions. One of the servers (located in St. Petersburg) acts as a router, the others are connected to it via a local network. The branches’ routers can access local network resources over a secure VPN connection.

In this brief overview, we described only the basics of building a small corporate network. In future articles, we’ll talk more in depth about VyOS’ capabilities and teach you how to more flexibly configure a firewall and port forwarding, allow traffic from protocols commonly used in corporate networks, and also look at the following topics:

  • organizing GRE tunnels;
  • L2TPv3 protocols;
  • QoS;
  • zone-based firewalls;
  • performance tuning a network interface;
  • VRRP.