How to build an OpenStack alternative: Step 2, secure the network

Posted on 2020-01-12 by ungleich virtualisation team

In the second step of building an OpenStack alternative we have a look on how to secure the network.

In the first step we described how to setup a protoype.

Note: the name of our OpenStack alternative is uncloud.

Securing the network - of what?

Users should be able to do what they want and not limited in their actions. On the other hand, users should be unable to disturb other users. It's very much like in real life.

General policy: no firewall

So for most of the user generated traffic there should be no firewall rules in uncloud. Users should be free to configure their own policies on the VM.

Network types

Before applying any security mechanism, we have to think about what kind of networks can exist in a cloud environment. We see two types of networks:

  • shared networks - more than one customer is in this network
  • private networks - only one customer has access in this network

Filtering IP address management packets

So when we share a network, we don't want one customer to be able to assign IP addresses to other customers. Instead IP addresses should only be assigned from the operator.

This means that we need to prevent rogue

In our prototype we are using nftables instead of iptables for firewalling, but the rules can be translated from one to another firewall system.

To drop router advertisements, we can use the following rule:

icmpv6 type nd-router-advert drop

To drop DHCPv6 server answers we can use

ip6 version 6 udp sport 547 drop

And finally to prevent DHCPv4 server anwers, we use

ip  version 4 udp sport 67 drop

Note: while uncloud does not use IPv4 or DHCPv4 to the VMs, a rogue DHCPv4 server might still trick other VMs into assigning themself an IPv4 address. So we also need to block this one.

Filtering MAC and IP spoofing

A VM should not be able to spoof the MAC address or IP address of another machine. We can achieve this by adding a chain specific for each VM network interface:

iifname tap1 ether saddr 02:00:f0:a9:c4:4e ip6 saddr 2a0a:e5c1:111:888:0:f0ff:fea9:c44e accept

With this we can even allow routing a network to a VM and allowing it to use any IPv6 address in that network:

iifname v343a-0 ether saddr 02:00:f0:a9:c4:4f ip6 saddr 2a0a:e5c1:111:888:0:f0ff:fea9:c44f accept
iifname v343a-0 ether saddr 02:00:f0:a9:c4:4f ip6 saddr 2a0a:e5c1:111:1234::/64 accept

Putting it all together

The following code is a full nftable ruleset for securing the VM network traffic. Note that it uses the prerouting hook so that we can use the ibrname statement. This is necessary because we don't want to filter after routing or in a forwarding mode, but we want to already filter it prerouting (hence the name).

flush ruleset

table bridge filter {
    chain prerouting {
        type filter hook prerouting priority 0;
        policy accept;

        ibrname br100 jump br100
    }

    chain br100 {
        # Allow all incoming traffic from outside
        iifname vxlan100 accept

        # Default blocks: router advertisements, dhcpv6, dhcpv4
        icmpv6 type nd-router-advert drop
        ip6 version 6 udp sport 547 drop
        ip  version 4 udp sport 67 drop

        jump br100_vmlist
        drop
    }
    chain br100_vmlist {
        # VM1
        iifname tap1 ether saddr 02:00:f0:a9:c4:4e ip6 saddr 2a0a:e5c1:111:888:0:f0ff:fea9:c44e accept

        # VM2
        iifname v343a-0 ether saddr 02:00:f0:a9:c4:4f ip6 saddr 2a0a:e5c1:111:888:0:f0ff:fea9:c44f accept
        iifname v343a-0 ether saddr 02:00:f0:a9:c4:4f ip6 saddr 2a0a:e5c1:111:1234::/64 accept
    }
}

Status

With this second step we create the basis for actually running VMs that we (as an operator) don't trust. So now we have a prototype and we have network security. We probably want to begin to automate things in the next step.