Dropping Packets from Unikernels

For quite some time now ops has auto-generated firewall rules for various cloud providers such as GCP and AWS.

Everytime you see an ops example such as 'ops instance create -p 8080' you are affectively punching a hole to allow the outside world to talk to your unikernel over that port.

This works well when you want to expose a unikernel to the wild wild west of the internet - not that the unikernel in question is listening on more than one port typically regardless. What about when it's just talking to other hosts on the same class c in an internal vpc? Or what if you don't want to or *can't* adjust the firewall rules for that host from the provider side? Some engineering teams have separate deploy, networking and security teams and they can sometimes all impose their own rules and will.

There is also the situation where you may have setup appropriate fw rules already but you'd like to defend against certain types of SSRF attacks that you might be otherwise vulnerable to.

This is where the new 'firewall' klib comes into play. Rather than relying on the cloud provider to enforce network security tags you can insist upon it at the Nanos instance level as well. This is unique since because in unikernel land the app and the instance are the same thing. This is very different as compared to a container or a normal linux instance. In linux one might use iptables, and docker will use that as well (some might say misuse). We don't use overlay networks or any other complex routing as our application is our instance. There is one and only one application per virtual machine. This also answers the question of "where is the kubernetes/orchestration for unikernels?" - in general you don't need one as again, we don't need to create additional layers and instead get to rely on the standard cloud primitives that are everywhere and which result in not just much better latency/throughput than containers but even standard debian/arch vms.

Before we dive in just to reiterate - you do not need to use this klib as general practice. Merely by using unikernels you instantly have a much more sane setup than a comparable container or linux vm. This is for more fine-grained access control of the instance or for special cases. As of this writing we'll assume you know how to run simple webservers with ops and you can follow along with this nanos version:

ops run --nanos-version=592791c -c fw.config.json -p 8080 g

(If you are reading in the future you can just not include that nanos-version.) Let's look at a few examples:

Accept any tcp packets for destination port 8080 - drop everything else:

As you can see here I've included a rule to talk to DHCP (udp port 67) which you'll probably want to include for cloud deploys. If you are running locally you may not need this.

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"tcp": {"dest": "8080"}, "action": "accept"},
        {"udp": {"src": "67"}, "action": "accept"},
        {"action": "drop"}
      ]
    }
  }
}

Accept from source 10.0.2.2 (qemu host address) going to destination port 8080 - drop everything else:

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"ip": {"src": "10.0.2.2"}, "action": "accept"},
        {"tcp": {"dest": "8080"}, "action": "accept"},
        {"udp": {"src": "67"}, "action": "accept"},
       {"action": "drop"}
      ]
    }
  }
}

Drop all packets coming from 10.0.2.2:

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"ip": {"src": "10.0.2.2"}, "action": "drop"}
      ]
    }
  }
}

Drop IPv4 packets coming from addresses other than 10.0.2.2:

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"ip": {"src": "!10.0.2.2"}, "action": "drop"}
      ]
    }
  }
}

Drop all UDP packets coming from IP addresses in the range 10.0.2.0-10.0.2.255:

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"ip": {"src": "10.0.2.0/24"}, "udp": {}, "action": "drop"}
      ]
    }
  }
}

Drop all packets coming from IPv6 address FE80::FF:7762:

(Yes, we've got IPV6 - hell we got DHCPV6 which quite a few normal gpos/clouds don't have.)

{
  "RunConfig":{
    "Klibs":["firewall"]
   },
  "ManifestPassthrough": {
    "firewall": {
      "rules": [
        {"ip6": {"src": "FE80::FF:7762"}, "action": "drop"}
      ]
    }
  }
}

Now you too can implement find-grained network policy control over your unikernel infrastructure.

Deploy Your First Open Source Unikernel In Seconds

Get Started Now.