smartos zone firewall

So like me, you may have public facing SmartOS machines and you want to lock down. You probably already have existing dedicated firewalls on your network perimeter. Even so, you should probably further secure your Zone instances by using SmartOS’s powerful built in virtual network filter. Before we begin, please be aware that this applies to all Zone machines, but will only work on KVM virtual machines if you are using a SmartOS version released after the end of March 2014.

Concept Overview

A single comprehensive tool is used to manage all filtering rules on SmartOS, it is called “fwadm”. For a long time there was no MAN page available thus me and the cryptic “fwadm” tool were definitely NOT the best of friends. However, once I got my head around the fundamentals concepts – the fog cleared and it all made perfect sense. The firewall comprehensive rule syntax MAN page can be found here FWRULE and FWADM.

Rule Syntax

We are going to go through a list of rule parameters. I will be using colour highlighted sections as we progress through and build up our “syntax logic” fundamentals. We will then continue on to the actual steps in enabling, applying and testing firewall rules from the Global Zone.

Filtering Direction

Inbound / Ingress

e.g. FROM the internet TO your zone-vm
e.g. FROM another zone-vm TO your zone-vm

Outbound / Egress

e.g. FROM your zone-vm TO the internet
e.g. FROM your zone-vm TO another zone-vm

Protocols and Ports

Protocols – TCP, UDP, ICMP

e.g. FROM the internet TO your zone-vm tcp

Ports – the port number

e.g. FROM the internet TO your zone-vm tcp PORT 80

Action – Allow or Block

Allow

– Traffic matching this rule will be Allowed
e.g. FROM the internet TO your zone-vm ALLOW tcp PORT 80

Block

– Traffic matching this rule will be Blocked
e.g. FROM the internet TO your zone-vm BLOCK tcp PORT 80

Target Type

all vms

e.g. FROM any TO all vms ALLOW tcp PORT 80

any

e.g. FROM any TO all vms ALLOW tcp PORT 80

vm – <uuid>

e.g. FROM subnet 10.8.0.0/16 TO vm 0f570678-c007-4610-a2c0-bbfcaab9f4e6 ALLOW tcp PORT 443

ip – <IP address>

e.g. FROM any TO ip 10.2.0.1 ALLOW tcp PORT 25

subnet – <subnet CIDR>

e.g. FROM subnet 10.8.0.0/16 TO any ALLOW tcp PORT 443

tag – <tag name>

e.g. FROM all vms TO tag syslog ALLOW udp PORT 514

tag – <tag name=tag value>

e.g. FROM all vms TO tag role = www ALLOW udp PORT 514

a target list of up to 32 of the above – <target>

e.g. FROM any TO (subnet 10.2.2.0/24 OR ip 10.3.0.1) ALLOW tcp PORT 25

FWADM in Action

Alrighty then, lets get going with the nitty gritty of using “fwadm”. Thankfully “fwadm” supports tab completion just like “vmadm” does so tab completing those long UUID’s is easy.

Most importantly the firewall will be disabled by default for newly created Zones unless you have specifically enabled and configured the firewall in the JSON payload file passed to “vmadm” upon its creation. First we will take a look at the rules that are enabled by default in the Global Zone.

There are 2 types of rules: Global and zone specific rules.There is no ordering to firewall rules. For incoming traffic, the least restrictive rule applies. For outgoing traffic, the most restrictive rule applies. ICMP echo Global rule is enabled by default for all inbound ping requests. In addition when a zone firewall is enabled there is a default pass rule for all outbound traffic.

Global Firewall Rule

A global rule applies to every zone on that hypervisor. If the firewall is enabled on a vm – all “Global Rules” immediately apply.

Zone Specific Firewall Rule

This is a rule that is related both to a specific zone vm as well as the owner_uuid of the person to whom it belongs. In my testing I discovered that if a vm does not have a “owner_uuid” set – I simply could not get the rule to work. I guess the logic here is that every machine should have an owner_uuid – and all non-global rules should belong to a specific owner_uuid.

So in other words if you blow away a customer (please no firearms), his firewall rules should get destroyed in the process.

Start the Zone Firewall

[root@smartosn3 ~]# vmadm list
UUID                                  TYPE  RAM      STATE             ALIAS
ad42decb-31df-47c6-b5fc-f6cc5e4f3e02  OS    1024     stopped           zurmo-2.7-virgin
dc853525-2429-42e7-8ec2-12f60b13e517  OS    1024     running           worpress-testm
1bdee4bd-f317-4cad-958a-7b767b291153  KVM   4096     stopped           windows 7 test

[root@smartosn3 ~]# fwadm list
UUID                                 ENABLED RULE
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

[root@smartosn3 ~]# fwadm status dc853525-2429-42e7-8ec2-12f60b13e517
stopped

[root@smartosn3 ~]# fwadm start dc853525-2429-42e7-8ec2-12f60b13e517
Firewall started for VM dc853525-2429-42e7-8ec2-12f60b13e517

[root@smartosn3 ~]# fwadm status dc853525-2429-42e7-8ec2-12f60b13e517
running

[root@smartosn3 ~]# fwadm list dc853525-2429-42e7-8ec2-12f60b13e517
UUID                                 ENABLED RULE
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

[root@smartosn3 ~]# fwadm status -v dc853525-2429-42e7-8ec2-12f60b13e517
ipf: v4.1.9 (592)
kernel: v4.1.9
running: true
log flags: 0 = none set
default: pass all, Logging: available
active list: 1
feature mask: 0x107

[root@smartosn3 ~]#

Once the firewall was started on the zone dc853525-2429-42e7-8ec2-12f60b13e517 I could still ping it from the outside but I could NO longer SSH to it. The reason ping works is because of the global firewall rule:
+++
c905194c-deec-411c-8652-dc4245925b39 true FROM any TO all vms ALLOW icmp TYPE 8 CODE 0
+++
Rules can either be enabled or disabled (true) or (false). Therefore you do not specifically need to delete a rule – to deactivate, you can simply disable it. Also important to observe is that each rule gets its own unique UUID.

➜  ~  ping 10.1.1.42
PING 10.1.1.42 (10.1.1.42): 56 data bytes
64 bytes from 10.1.1.42: icmp_seq=0 ttl=255 time=0.354 ms
64 bytes from 10.1.1.42: icmp_seq=1 ttl=255 time=0.195 ms
^C
--- 10.1.1.42 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.195/0.274/0.354/0.080 ms
➜  ~  ssh root@10.1.1.42
ssh: connect to host 10.1.1.42 port 22: Operation timed out

Now lets add an additional global rule to allow SSH TCP 22 by default to ALL vms. We add it as a Global rule with the “-g” switch and enable it with the the “-e” switch.

fwadm add -g -e FROM any TO all vms ALLOW tcp PORT 22

+++

[root@smartosn3 ~]# fwadm add -g -e FROM any TO all vms ALLOW tcp PORT 22
Added rules:
597785df-e141-47bc-91a0-bc04c8861e18 true    FROM any TO all vms ALLOW tcp PORT 22

[root@smartosn3 ~]# fwadm list dc853525-2429-42e7-8ec2-12f60b13e517
UUID                                 ENABLED RULE
597785df-e141-47bc-91a0-bc04c8861e18 true    FROM any TO all vms ALLOW tcp PORT 22
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

[root@smartosn3 ~]#

Now we can see the rule is in effect and lets see if we are now able to SSH to that machine? Yup looks like its working.

➜  ~  ssh root@10.1.1.42
ssh: connect to host 10.1.1.42 port 22: Operation timed out
➜  ~  ssh root@10.1.1.42
Last login: Mon Aug 11 22:59:52 2014
 __        __            _
 \ \      / /__  _ __ __| |_ __  _ __ ___  ___ ___
  \ \ /\ / / _ \| '__/ _` | '_ \| '__/ _ \/ __/ __|
   \ V  V / (_) | | | (_| | |_) | | |  __/\__ \__ \
    \_/\_/ \___/|_|  \__,_| .__/|_|  \___||___/___/
                          |_|
                    Instance (base64 13.4.2)

[root@worpress-testm ~]#

Ok lets disable then delete that Global SSH rule, as we may not want SSH open to all zones. Lets set up some zone specific rules. We will need to ensure that the zone has a owner_uuid set. If it does not we can simply generate one and assign it to the zone vm.

[root@smartosn3 ~]# fwadm list  dc853525-2429-42e7-8ec2-12f60b13e517
UUID                                 ENABLED RULE
597785df-e141-47bc-91a0-bc04c8861e18 -       FROM any TO all vms ALLOW tcp PORT 22
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

[root@smartosn3 ~]# fwadm delete 597785df-e141-47bc-91a0-bc04c8861e18
Deleted rules:
597785df-e141-47bc-91a0-bc04c8861e18 false   FROM any TO all vms ALLOW tcp PORT 22

[root@smartosn3 ~]# fwadm list dc853525-2429-42e7-8ec2-12f60b13e517
UUID                                 ENABLED RULE
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

[root@smartosn3 ~]# vmadm get dc853525-2429-42e7-8ec2-12f60b13e517 | grep owner_uuid

[root@smartosn3 ~]# uuid
81311a70-2161-11e4-a81c-eb29e4f2f279

[root@smartosn3 ~]# vmadm update dc853525-2429-42e7-8ec2-12f60b13e517 owner_uuid=81311a70-2161-11e4-a81c-eb29e4f2f279
Successfully updated VM dc853525-2429-42e7-8ec2-12f60b13e517

[root@smartosn3 ~]# vmadm get dc853525-2429-42e7-8ec2-12f60b13e517 | grep owner_uuid
  "owner_uuid": "81311a70-2161-11e4-a81c-eb29e4f2f279",

Next we will prepare a JSON payload file with a specific rule and pass it to “fwadm”. In the file we specify that the rule should be enabled as well as the owner_uuid who owns the rule. We also associate it exclusively with our vm’s uuid and allow in SSH, HTTP, HTTPS. Lets first submit it with the –dryrun option to confirm there are no errors.

fwadm add --dryrun -f myfw-rule.json

myfw-rule.json

{
    "enabled": true,
    "owner_uuid": "81311a70-2161-11e4-a81c-eb29e4f2f279",
    "rule": "FROM any TO vm dc853525-2429-42e7-8ec2-12f60b13e517 ALLOW tcp (PORT 80 AND PORT 443 and PORT 22)"
}
[root@smartosn3 ~]# vi myfw-rule.json

[root@smartosn3 ~]# fwadm add --dryrun -f myfw-rule.json
Added rules:
5fd1fe00-9da4-4b44-808a-ae835cab03ba true    FROM any TO vm dc853525-2429-42e7-8ec2-12f60b13e517 ALLOW tcp (PORT 22 AND PORT 443 AND PORT 80)

[root@smartosn3 ~]# fwadm add -f myfw-rule.json
Added rules:
77c1aa20-b37b-4d89-8d59-6a6f9c90e565 true    FROM any TO vm dc853525-2429-42e7-8ec2-12f60b13e517 ALLOW tcp (PORT 22 AND PORT 443 AND PORT 80)

[root@smartosn3 ~]# fwadm list dc853525-2429-42e7-8ec2-12f60b13e517
UUID                                 ENABLED RULE
77c1aa20-b37b-4d89-8d59-6a6f9c90e565 true    FROM any TO vm dc853525-2429-42e7-8ec2-12f60b13e517 ALLOW tcp (PORT 22 AND PORT 80 AND PORT 443)
c905194c-deec-411c-8652-dc4245925b39 true    FROM any TO all vms ALLOW icmp TYPE 8 CODE 0

As you can see our new rules are applied and working. We can also list our rules in JSON format using the -j, which gives us additional information such as global vs non-global rules.

[root@smartosn3 ~]# fwadm list dc853525-2429-42e7-8ec2-12f60b13e517 -j
[
  {
    "enabled": true,
    "owner_uuid": "81311a70-2161-11e4-a81c-eb29e4f2f279",
    "rule": "FROM any TO vm dc853525-2429-42e7-8ec2-12f60b13e517 ALLOW tcp (PORT 22 AND PORT 80 AND PORT 443)",
    "uuid": "77c1aa20-b37b-4d89-8d59-6a6f9c90e565",
    "version": "1407767547179.078228"
  },
  {
    "enabled": true,
    "global": true,
    "rule": "FROM any TO all vms ALLOW icmp TYPE 8 CODE 0",
    "uuid": "c905194c-deec-411c-8652-dc4245925b39",
    "version": "1381543930726.002523"
  }
]

We have just touched the surface with all the myriad options available with “fwadm”. Hopefully this is enough of an overview to get you up and running. “Sup! – Go get dem zones locked down tight “son” and take care of yo business – yee-ha”