Adding VLAN Interfaces to Ubuntu

I’m in the process of rebuilding my home network, splitting the network into separate VLANs. My Ubuntu server is connected to a trunk port on my switch, and I need to create virtual interfaces to allow it to access all of the VLANs I’ve set up. It turns out this is fairly straightforward.

First we install the vlan and add the 8021q kernel module.

sudo apt-get install vlan
sudo modprobe 8021q

Next we can create the virtual interfaces, in my case they will share the enp1s0 interface:

sudo vconfig add enp1s0 10
sudo vconfig add enp1s0 20
sudo vconfig add enp1s0 30
sudo vconfig add enp1s0 40

Since I’m using DHCP for everything I set up /etc/network/interfaces as follows. You could alternatively set your virtual interfaces as static and manually configure the IP, netmask, gateway etc.

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto enp1s0
iface enp1s0 inet dhcp

auto enp1s0.10
iface enp1s0.10 inet dhcp
	vlan-raw-device enp1s0

auto enp1s0.20
iface enp1s0.20 inet dhcp
	vlan-raw-device enp1s0

auto enp1s0.30
iface enp1s0.30 inet dhcp
	vlan-raw-device enp1s0

auto enp1s0.40
iface enp1s0.40 inet dhcp
	vlan-raw-device enp1s0

We can now bring these interfaces up, and they should be reachable from their respective VLANs:

sudo ifup enp1s0.10
sudo ifup enp1s0.20
sudo ifup enp1s0.30
sudo ifup enp1s0.40

One issue I ran into was that I couldn’t access the virtual interfaces from other VLANs. For example a client on VLAN10 could ping this server on it’s VLAN10 address, but not on VLAN20. To get around this we need to change the Reverse Path Filtering setting in /etc/sysctl.d/10-network-security.conf.

The 3 values that can be set for the key rp_filter are:
0: No source address validation is performed and any packet is forwarded to the destination network
1: Strict Mode as defined in RFC 3074. Each incoming packet to a router is tested against the routing table and if the interface that the packet is received on is not the best return path for the packet then the packet is dropped.
2: Loose mode as defines in RFC 3074 Loose Reverse Path. Each incoming packet is tested against the route table and the packet is dropped if the source address is not routable through any interface. The allows for asymmetric routing where the return path may not be the same as the source path

In my case I want incoming packets on the VLAN interfaces to be able to route to other VLANS, so we can set this to 2.

# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks.
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.enp1s0.rp_filter=2
net.ipv4.conf.enp1s0/10.rp_filter=2
net.ipv4.conf.enp1s0/20.rp_filter=2
net.ipv4.conf.enp1s0/30.rp_filter=2
net.ipv4.conf.enp1s0/40.rp_filter=2

# Turn on SYN-flood protections.  Starting with 2.6.26, there is no loss
# of TCP functionality/features under normal conditions.  When flood
# protections kick in under high unanswered-SYN load, the system
# should remain more stable, with a trade off of some loss of TCP
# functionality/features (e.g. TCP Window scaling).
net.ipv4.tcp_syncookies=1

After restarting the networking service sudo service networking restart the server is now reachable on all interfaces.

Extending Boto3

All of Boto3’s resource and client classes are generated at runtime. This means that you cannot directly inherit and then extend the functionality of these classes because they do not exist until the program actually starts running.

It is still possible to extend boto3 using the events system, which allows us to run custom code when boto3 events triggered, or to provide default values. It also allows us to add additional classes to the base objects.

As an example, we can add a new class for ec2.Instance to inherit from with a convenience method for reading tags:

import boto3

class InstanceExtras(object):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def get_tag(self, tag, default=''):
        if self.tags:
            all_tags = [t for t in self.tags if t['Key'] == tag]
            if all_tags:
                return all_tags[0]['Value']
        return default

def add_custom_instance_class(base_classes, **kwargs):
    base_classes.insert(0, InstanceExtras)

session = boto3.Session(*args, **kwargs)
session.events.register(
    'creating-resource-class.ec2.Instance',
    add_custom_instance_class
)

This new session object can then be used normally, and whenever an ec2.Instance is returned it will inherit our new method.

ec2 = session.resource('ec2')
instance = ec2.instances(InstanceId='i-123456abc')
name = instance.get_tag('Name') # Will return the Name tag

Replacing Logitech Options with Hammerspoon

The recent security vulnerability in the Logitech Options app prompted me to see if I could achieve the same functionality without it. All I really care about is to bind the 4th and 5th buttons (the ones on the side by the second scroll wheel) to back and forward in Chrome, and the 6th button (the thumb rest) to open Mission Control. I’m already using Hammerspoon for a few things, so this seemed like the best place to start.

After a bit of digging it turns out that the thumb rest button is sending Ctrl + Alt + Tab, which can be easily bound to opening the Mission Control app:

hs.hotkey.bind({"alt", "ctrl"}, "Tab", function()
    hs.application.launchOrFocus("Mission Control.app")
end)

To capture the mouse buttons we can use hs.eventtap, and send the back and forward shortcuts if the current application is chrome:

hs.eventtap.new(hs.eventtap.event.types.middleMouseUp, function(event)

    button = event:getProperty(hs.eventtap.event.properties.mouseEventButtonNumber)

    current_app = hs.application.frontmostApplication()
    google_chrome = hs.application.find("Google Chrome")

    if (current_app == google_chrome) then
        if (button == 3) then
            hs.eventtap.keyStroke({"cmd"}, "[")
        end

        if (button == 4) then
            hs.eventtap.keyStroke({"cmd"}, "]")
        end
    end
end):start()

Using DUO Authentication Proxy with AWS Managed Microsoft Active Directory

I recently had to add a second factor to an AWS Workspaces environment. We use AWS Managed Microsoft AD for the Workspaces directory, which can be configured to call an external RADIUS server for secondary authentication. Since we are already using DUO for other systems, I used the Duo Authentication Proxy to provide this second factor.

The proxy needs to be built from source. For example, on Ubuntu:

apt-get install build-essential libssl-dev python-dev libffi-dev
wget https://dl.duosecurity.com/duoauthproxy-latest-src.tgz
tar xzf duoauthproxy-latest-src.tgz
cd duoauthproxy-*-src
make
cd duoauthproxy-build
./install

Configuration of the DUO client is fairly straightforward. We just need to update /opt/duoauthproxy/conf/authproxy.cfg with our DUO API credentials, the IP addresses of the two domain controllers, and the RADIUS secret we want to use. Note that directory services only supports a single RADIUS secret used by all domain controllers, so just enter the same one twice.

[duo_only_client]
; This section has no settings

[radius_server_auto]
client=duo_only_client
port=1812
ikey=<duo_integration_key>
skey=<duo_secret_key>
api_host=<duo_api_host>

radius_ip_1=<dc1_ip_address>
radius_secret_1=<radius_secret>
radius_ip_2=<dc2_ip_address>
radius_secret_2=<radius_secret>

failmode=secure
allow_concat=false
factors=push

Finally we can configure directory services to use the DUO proxy as a second factor. This is simplest in the console, but can also be done via the command line:

cat > settings.json <<EOF
{
    "RadiusServers": ["<dc1_ip_address>", "<dc2_ip_address>"],
    "RadiusPort": 1812,
    "RadiusTimeout": 30,
    "RadiusRetries": 4,
    "SharedSecret": "<radius_secret>",
    "AuthenticationProtocol": "PAP",
    "DisplayLabel": "DUO",
    "UseSameUsername": true
}
EOF

aws ds enable-radius --directory-id <directory-id> --cli-input-json file:///settings.json

DevOps Days 2018

“There are three types of lies: Lies, damned lies, and service status pages”

I had a great time at DevOps Days 2018 in Wellington earlier this week. Wellington really put on the weather (and craft beer), and the organisers ran an excellent conference. I really appreciated the decision to allow opting out of the conference T-Shirt in favour of a donation to charity. As much as I love my swag I really don’t need any more black T-Shirts with tech logos!

Jeff Smith opened the proceedings with Moving from Ops to DevOps: Centro’s Journey to the Promiseland, which had some great practical tips on measuring toil and making sure you’re asking the right questions. François Conil’s talk Monitoring that cares spoke about the end of user based monitoring, and humane, actionable alerts. I also really enjoyed Ryan McCarvill’s fascinating talk Fighting fires with DevOps on the challenges of fitting out fire trucks for Fire & Emergency NZ with a modern cloud based incident response system.

Matt Brown held a really interesting workshop on risk prioritisation from the point of view of a SRE. By calculating the expected ‘cost’ of an outage in downtime minutes per year, we can compare these against our error budget to determine if they fit our risk model.

Jessica DeVita closed out the conference with a deep dive into her research on retrospectives. After an incident we tend to put most of our attention ‘below the line’ of our systems diagrams, and far less ‘above the line’, at the people and processes operating those systems. One cannot exist without the other, so we need to strive for a culture of blamelessness and empathy in our incident response processes in order to learn about and improve the resiliency of our systems - above and below the line.

In no particular order, here’s a list of links mentioned that I still need to dive into properly, and a few books I’ve added to my reading list.

Drive
Daniel H. Pink

Most people believe that the best way to motivate is with rewards like money—the carrot-and-stick approach. That's a mistake, says Daniel H. Pink. In this provocative and persuasive new book, he asserts that the secret to high performance and satisfaction-at work, at school, and at home—is the deeply human need to direct our own lives, to learn and create new things, and to do better by ourselves and our world.

The Field Guide to Understanding 'Human Error'
Sidney Dekker

The Field Guide to Understanding ’Human Error’ will help you understand a new way of dealing with a perceived 'human error' problem in your organization. It will help you trace how your organization juggles inherent trade-offs between safety and other pressures and expectations, suggesting that you are not the custodian of an already safe system.

Testing in Devops
Katrina Clokie

As organisations shift to a culture of intense collaboration and rapid delivery, the expectations on testers are changing. What does testing look like in an environment with automated build and deployment pipelines? How does appetite for risk change once a product can be tested in production? Who should testers look to connect with across the organisation and how can they work together effectively to deliver quality software?