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.