Harden the Firewall

This module will use VM Resource Manager to slightly modify the firewalls’s configuration. In this case, we will simply use the run_executable method to execute a system-level command in our VM.

For the sake of this tutorial, let’s pretend the system administrator of the ACME network wants to harden the firewall. Therefore, they have decided to only allow access to the machine through the physical console and therefore the SSH server needs to be turned off. Since the firewall is a VyOS Helium118 router, the command to turn off SSH is simply service ssh stop. Configuring a VM to run a command like this only requires calling the run_executable function on the firewall’s object in the graph.

Note

The technically better way to do this would be to modify the a router’s configuration to ensure that the SSH server is disabled. However, we’re using the service system command to make this tutorial more generally applicable.

Modifying the Topology

The firewall was created in the ACME topology’s build_front() function which should look like this:

def build_front(self, ext_ip):
    """Build the ACME infrastructure that is Internet-facing.

    This method will create the following topology::

            switch -- gateway -- switch -- firewall
        (ACME-EXTERNAL)         (GW-FW)

    Args:
        ext_ip (netaddr.IPAddress): The external IP address for the gateway
            (e.g. its Internet facing IP address).

    Returns:
        vyos.Helium118: The Firewall object.
    """

    # Build the gateway
    gateway = Vertex(self.g, "gateway.acme.com")
    gateway.decorate(Helium118)

    # Create the external switch
    ext_switch = Vertex(self.g, name="ACME-EXTERNAL")
    ext_switch.decorate(Switch)

    # Connect the gateway to the external switch
    gateway.connect(
        ext_switch,  # The "Internet" facing Switch
        ext_ip,  # The external IP address for the gateway (e.g. 1.0.0.1)
        self.external_network.netmask  # The external subnet mask (e.g. 255.255.255.0)
    )

    # Build a switch to connect the gateway and firewall
    gateway_firewall_switch = Vertex(self.g, name="GW-FW")
    gateway_firewall_switch.decorate(Switch)

    # Build the firewall
    firewall = Vertex(self.g, "firewall.acme.com")
    firewall.decorate(Helium118)

    # Create a network and a generator for the network between
    # the gateway and firewall.
    gateway_firewall_network = next(self.internal_subnets)
    gateway_firewall_network_iter = gateway_firewall_network.iter_hosts()

    # Connect the gateway and the firewall to their respective switches
    # We will use ``ospf_connect`` to ensure that the OSPF routes are propagated
    # correctly (as we want to use OSPF as routing protocol inside of the ACME network).
    gateway.ospf_connect(
        gateway_firewall_switch,
        next(gateway_firewall_network_iter),
        gateway_firewall_network.netmask,
    )
    firewall.ospf_connect(
        gateway_firewall_switch,
        next(gateway_firewall_network_iter),
        gateway_firewall_network.netmask,
    )
    return firewall

We need to add the following run_executable call to the fw object:

firewall.run_executable(-50, "/usr/sbin/service", "ssh stop")

This will run the service command at schedule time -50. It is not strictly required that the absolute path to the program be specified, but it is far safer do so rather than making any assumptions about how the VM environment will resolve program names. The modified build_front() function should now look like this (specifically, the addition of line 39):

 1def build_front(self, ext_ip):
 2    """Build the ACME infrastructure that is Internet-facing.
 3
 4    This method will create the following topology::
 5
 6            switch -- gateway -- switch -- firewall
 7        (ACME-EXTERNAL)         (GW-FW)
 8
 9    Args:
10        ext_ip (netaddr.IPAddress): The external IP address for the gateway
11            (e.g. its Internet facing IP address).
12
13    Returns:
14        vyos.Helium118: The Firewall object.
15    """
16
17    # Build the gateway
18    gateway = Vertex(self.g, "gateway.acme.com")
19    gateway.decorate(Helium118)
20
21    # Create the external switch
22    ext_switch = Vertex(self.g, name="ACME-EXTERNAL")
23    ext_switch.decorate(Switch)
24
25    # Connect the gateway to the external switch
26    gateway.connect(
27        ext_switch,  # The "Internet" facing Switch
28        ext_ip,  # The external IP address for the gateway (e.g. 1.0.0.1)
29        self.external_network.netmask  # The external subnet mask (e.g. 255.255.255.0)
30    )
31
32    # Build a switch to connect the gateway and firewall
33    gateway_firewall_switch = Vertex(self.g, name="GW-FW")
34    gateway_firewall_switch.decorate(Switch)
35
36    # Build the firewall
37    firewall = Vertex(self.g, "firewall.acme.com")
38    firewall.decorate(Helium118)
39    firewall.run_executable(-50, "/usr/sbin/service", "ssh stop")
40
41    # Create a network and a generator for the network between
42    # the gateway and firewall.
43    gateway_firewall_network = next(self.internal_subnets)
44    gateway_firewall_network_iter = gateway_firewall_network.iter_hosts()
45
46    # Connect the gateway and the firewall to their respective switches
47    # We will use ``ospf_connect`` to ensure that the OSPF routes are propagated
48    # correctly (as we want to use OSPF as routing protocol inside of the ACME network).
49    gateway.ospf_connect(
50        gateway_firewall_switch,
51        next(gateway_firewall_network_iter),
52        gateway_firewall_network.netmask,
53    )
54    firewall.ospf_connect(
55        gateway_firewall_switch,
56        next(gateway_firewall_network_iter),
57        gateway_firewall_network.netmask,
58    )
59    return firewall

Once the topology is relaunched and all VMs are configured, use a VNC client in order to access the firewall VM:

$ firewheel vm list name=firewall vnc hostname

Once you are in the VM, run the following command to verify that the SSH server is off:

$ sudo service ssh status

A message should appear that the command “failed” since no PID file was found for SSH. This indicates that SSH is no longer running (otherwise there would be an active PID file) which means our command was successful.