Firewalld Rich Rules basics

This tutorial will help you to get started with the firewalld configuration. Basics on zones and rich rules are presented.

What we do

The shell provisioner will ensure that on all hosts firewalld and curl are installed. For “host_protected” the provisioner will install nginx for demo purposes, too. Furthermore, the firewall will configured on “host_protected”.

Every host has two interfaces NAT (enp0s3) and host-only (enp0s8). The provisioner will not touch the NAT interface (zone: public) rules! Only the host-only interface (zone: home) rules will modified!

# show result configuration public (local)
$ vagrant ssh host_protected -c 'sudo firewall-cmd --list-all --zone=public'
...
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  sourceports:
  icmp-blocks:
  rich rules:

# show result configuration home (local)
$ vagrant ssh host_protected -c 'sudo firewall-cmd --list-all --zone=home'
...
home (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s8
  sources:
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  sourceports:
  icmp-blocks:
  rich rules:
    rule family="ipv4" source address="192.168.33.10" service name="http" accept
    rule family="ipv4" source address="192.168.33.20" service name="ssh" accept

Project

Here are all needed files…

---
- name: host_http_access
  ip: 192.168.33.10
  hostname: http.local
- name: host_ssh_access
  ip: 192.168.33.20
  hostname: ssh.local
- name: host_protected
  ip: 192.168.33.30
  hostname: protected.local

Please add your values for box name/url!

# -*- mode: ruby -*-
# vi: set ft=ruby :

require 'yaml'

Vagrant.require_version ">= 1.9.3"
machines = YAML.load_file('hosts.yml')

Vagrant.configure("2") do |config|

  machines.each do |machines|

    config.vm.define machines["name"] do |machine|

      # disable ssh key update
      machine.ssh.insert_key = false

      # vagrant box name
      machine.vm.box = ""

      # vagrant box url
      machine.vm.box_url = ""

      # disable box update
      machine.vm.box_check_update = false

      # set hostname
      machine.vm.hostname = machines["hostname"]

      # disable synced_folder
      machine.vm.synced_folder ".", "/vagrant", disabled: true

      # 2nd network interface (private)
      machine.vm.network "private_network", ip: machines["ip"]

      # virtualbox settings
      machine.vm.provider :virtualbox do |vb|
        vb.name = machines["name"]
        vb.cpus = 1
        vb.memory = '1024'
        vb.gui = false
      end

      # run shell provisioner
      if machines["name"] == 'host_protected'
        machine.vm.provision "shell", path: "provisioner.sh", :args => "protected"
      else
        machine.vm.provision "shell", path: "provisioner.sh"
      end

    end

  end

end
#! /usr/bin/env bash

# install firewalld and curl
sudo yum install -y firewalld curl

# enable firewalld
sudo systemctl enable firewalld

# start firewalld
sudo systemctl start firewalld

# configure firewalld rich rules
if [ "${1}" == "protected" ]; then
  # install epel-release
  sudo yum install -y epel-release

  # install nginx
  sudo yum install -y nginx

  # enable nginx
  sudo systemctl enable nginx

  # start nginx
  sudo systemctl start nginx

  # change enp0s8 to home zone
  sudo firewall-cmd --zone=home --change-interface=enp0s8 --permanent

  # restart firewalld service
  sudo systemctl restart firewalld

  # remove all services form zone home
  sudo firewall-cmd --zone=home --remove-service dhcpv6-client --permanent
  sudo firewall-cmd --zone=home --remove-service mdns --permanent
  sudo firewall-cmd --zone=home --remove-service samba-client --permanent
  sudo firewall-cmd --zone=home --remove-service ssh --permanent

  # add rich rules
  sudo firewall-cmd --zone=home --add-rich-rule='rule family="ipv4" service name="http" source address="192.168.33.10" accept' --permanent
  sudo firewall-cmd --zone=home --add-rich-rule='rule family="ipv4" service name="ssh" source address="192.168.33.20" accept' --permanent

  # reload firewall
  sudo firewall-cmd --reload
fi

Usage

# start vagrant environment (local)
$ vagrant up

# show status (optional - local)
$ vagrant status
...
Current machine states:

host_http_access          running (virtualbox)
host_ssh_access           running (virtualbox)
host_protected            running (virtualbox)

# ssh into host_http_access (local)
$ vagrant ssh host_http_access

# try http via curl (host_http_access)
$ curl -I http://192.168.33.30

# try ssh (host_http_access)
$ ssh vagrant@192.168.33.30

# ssh into host_ssh_access (local)
$ vagrant ssh host_ssh_access

# try http via curl (host_ssh_access)
$ curl -I http://192.168.33.30

# try ssh (host_ssh_access)
$ ssh vagrant@192.168.33.30

# destroy vagrant environment
$ vagrant destroy -f

Note: before you destroy the vagrant environment, have a look on zones xml files for “host_protected”!

# ssh into host_protected (local)
$ vagrant ssh host_protected

# change to root (host_protected)
$ sudo su -

# change directory
$ cd /etc

# cat actual zone xml files
$ cat firewalld/zones/*.xml