-
Notifications
You must be signed in to change notification settings - Fork 5
Example for ufw
Ufw - the UncomplicatedFirewall - is a popular, simple firewall for Linux. This page shows how to use Tstconfig to test its configuration automatically.
Ufw's runtime configuration can be queried as follows:
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22 LIMIT IN Anywhere
22 (v6) LIMIT IN Anywhere (v6)
The first four lines (the header) present the general configuration of ufw. The rest of the lines are the rules, which we'll look at in a section below.
To test the header, create a definition file called ufw.tstconfig with the
following content:
# The command to query ufw's runtime configuration
command sudo /usr/sbin/ufw status verbose
# read the first four lines, ignore everything else
read_lines 4
# The syntax is a simple key-value map
parse_mode keyvalue
# The key and values are separated by ':'
key_separator :
Now we're ready to add some assertions:
# Check that status is active
property Status
assert_eq active
# Check the default filtering rule
property Default
assert_eq deny (incoming), allow (outgoing), disabled (routed)
As you can see, property selects the property to be tested and assert_eq
tests for a specific value.
To run the tests, save the file and execute:
$ tstconfig ufw.tstconfig
If you get a report like the following:
Tstconfig 0.2
Reading definition file: ufw.tstconfig
ASSERTION FAILED
Command: sudo /usr/sbin/ufw status verbose
Property: Default
Value: allow (incoming), allow (outgoing), disabled (routed)
Assertion: assert_eq deny (incoming), allow (outgoing), disabled (routed)
SUMMARY REPORT: FAIL
Assertions tested: 2
Assertions passed: 1
Assertions failed: 1
Errors: 0
...then it means that some assertions failed (for property Default in the example). Reconfigure ufw accordingly and rerun the test. You should finally get a success report like the following:
Tstconfig 0.2
Reading definition file: ufw.tstconfig
SUMMARY REPORT: PASS
Assertions tested: 2
Assertions passed: 2
Assertions failed: 0
Errors: 0
Let's go back to the output of sudo ufw status verbose:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22 LIMIT IN Anywhere
22 (v6) LIMIT IN Anywhere (v6)
After the header, we find a table presenting the currently configured rules. The table is made of three columns (To, Action and From). The table is formatted so that the values start at fixed positions (0, 27 and 39). The interesting stuff starts al line eight, so the first seven lines can be ignored.
With this in mind, we're ready to add a few lines to the ufw.tstconfig file:
### Test the firewall rules
# Re-read the runtime configuration
command sudo /usr/sbin/ufw status verbose
# This time ignore the first seven lines then read the rest
skip_header_lines 7
# A fixed-position table with values starting at position 0, 27 and 39
parse_mode fixed
positions 0 27 39
When the format is a fixed-position table, the first column is interpreted as the property name, while the rest of the columns as property values. We're now ready for the assertions:
property 22
assert_eq "LIMIT IN" Anywhere
property "22 (v6)"
assert_eq "LIMIT IN" "Anywhere (v6)"
If we want to check that these are the only two rules, we can add the following assertion:
section_size
assert_eq 2
Run the test as usual with tstconfig ufw.tstconfig
In the previous example, ufw was configured to allow traffic directed to ssh. If we had other rules for other protocols (http, smtp, etc) the situation would be conceptually similar and we could add more assertions to test these other rules.
Instead, a more interesting scenario is when we have more than one rule for the same port. Let's assume we had the following firewall rules:
To Action From
-- ------ ----
22 LIMIT IN Anywhere
22 DENY IN 192.168.56.102
22 (v6) LIMIT IN Anywhere (v6)
There are two rules for port 22. One is the generic rule that applies to all From addresses (Anywhere). The other applies only to address 192.168.56.102. We need a way to test the values not simply for a given port, but for a combination of port and From address.
The solution is to tell Tstconfig to rearrange the columns in an order that is more useful for our purposes:
columns 0 2 1
This command re-maps the columns so that they can now be read in this order: To, From, Action. We can now write the assertions in a different way:
# Check the combination of port 22 / from Anywhere
property 22 Anywhere
assert_eq "LIMIT IN"
# Check the combination of port 22 / from 192.168.56.102
property 22 192.168.56.102
assert_eq "DENY IN"
# Check the combination of port 22 (v6)/ from Anywhere (v6)
property "22 (v6)" "Anywhere (v6)"
assert_eq "LIMIT IN"
Notice the peculiar use of property and assert_eq. In a table with three
columns (To, From, Action), the first two (To, From) are used as a property name
while the last one (Action) as the property value.
The complete ufw.tstconfig should now look like shown below. Feel free to
customise it to your needs:
### Test the status header
# The command to query ufw's runtime configuration
command sudo /usr/sbin/ufw status verbose
# read the first four lines, ignore everything else
read_lines 4
# The syntax is a simple key-value map
parse_mode keyvalue
# The key and values are separated by ':'
key_separator :
# Check that status is active
property Status
assert_eq active
# Check the default filtering rule
property Default
assert_eq deny (incoming), allow (outgoing), disabled (routed)
### Test the firewall rules
# Re-read the runtime configuration
command sudo /usr/sbin/ufw status verbose
# This time ignore the first seven lines then read the rest
skip_header_lines 7
# A fixed-position table with values starting at position 0, 27 and 39
parse_mode fixed
positions 0 27 39
# Rearrange the columns so they are: To From Action
columns 0 2 1
# Check the combination of port 22 / from Anywhere
property 22 Anywhere
assert_eq "LIMIT IN"
# Check the combination of port 22 / from 192.168.56.102
property 22 192.168.56.102
assert_eq "DENY IN"
# Check the combination of port 22 (v6)/ from Anywhere (v6)
property "22 (v6)" "Anywhere (v6)"
assert_eq "LIMIT IN"
# Check that there are only three rules
section_size
assert_eq 3