Alpine Wall

From Alpine Linux
This material is obsolete ...

Please feel free to help us make an up-to-date version. (Discuss)

This page is a design and implementation plan for a new firewall management framework. The new framework addresses the limitations of Shorewall, which is probably the most common solution used with Alpine.

Proposal

We evaluated serveral existing open source projects, none of which satisfied our demanding taste. The existing solutions are either too tied to specific (router) distributions, targeted to home users (with too many assumptions built-in), or depedent on bloated frameworks (usually Perl). Moreover, we would like to keep management of firewall settings and activation of such settings as two separate workflows, which would facilitate centralized management of firewall rules.

As no readily available solution was found, the proposal is to implement a new management framework for iptables, which would integrate with the Alpine Configuration Framework (ACF). The framework is hereafter referred to as the Alpine Wall (awall).

Design

Awall would consist of three major components: data model, front-end, and back-end. It also implements a plug-in architecture, which allows extending the data model and functionality, in order to simplify common organization-specific administrative tasks.

The data model would describe the firewall configuration using concepts and terminology that is roughly compatible with Shorewall. It would also borrow some useful concepts from other firewall solutions we evaluated, such as the Service concept as defined in the Turtle Firewall (but generalized a bit). Awall plug-ins can contain schema extension modules augmenting the basic model provided by the framework.

The back-end is responsible for translating the model's data into configuration files, most notably the files that can be read by iptables-restore and ip6tables-restore. Moreover, it can produce files into e.g. /etc/modprobe.d and /etc/sysctl.d if necessary. When a plug-in extends the data model, it must also provide a back-end module that interprets model extension and translates the data into iptables and other rules. The framework includes a module for interpreting the base model. The framework is responsible for ordering and aggregating the results produced by all modules into actual configuration files.

The front-end is essentially an ACF module which allows editing the data model and activating the changes with the help of the back-end. The front-end implements also a fallback mechanism that prevents the operator from locking himself out by a faulty configuration. The configuration data is stored in text files which can be directly edited. The front-end provides a command line tool for validating and activating the configuration after manual changes.

Base Model

The basic data model could roughly look like as follows:

Zone
interface*, subnet*
Service
(protocol, port*)+
Forwarding policy
Zone:in*, Zone:out*, accept/reject/drop, masq_on/masq_off
Filtering rule
Zone:in*, Zone:out*, Service+, accept/reject/drop, conn_limit?, flow_limit?
NAT rule
snat/dnat, Zone:in*, Zone:out*, Service, ip4_range, port_range?

Subnets in zone definitions can be declared using IPv4/IPv6 addresses (CIDR notation), domain names, or as references to ipsets. A domain name can resolve to one or more IP addresses. The referred ipsets may be managed manually or by some other tool.

If a packet with source address a arrives on interface i, it is considered to originate from zone Z = (I, S) (where I is the set of interfaces and S is the set of subnets) if and only if I includes i, and a belongs to any subnet of S. In zone definitions, I would default to the set of all interfaces and S to {0.0.0.0/0, ::}. The destination zone would be defined in a similar way based on the packet's destination address and interface.

Implementation Considerations

The data model should preferably be based on some existing format, such as JSON, XML, or YAML. In order to allow extensions to the data model, awall must define some kind of schema language. This language would embed the necessary information the front-end needs to automatically generate a user interface for the extension. For example, the help texts shown to the user would be placed in the schema modules.

Ideally, the base model would be described using the very same language as the model extensions, but it would impose quite demanding requirements on the language, e.g. support for complex data types. If we select this approach and model the data using XML, we could use XML Schema as the basis. There is also an (expired) Internet Draft on JSON Schema, but there seems to be no existing validator implementation in C or Lua.

Even though elegant from architecture point of view, it is unlikely that support for complex data types would be required by typical extensions. In most cases, a set of global variables of primitive types would suffice. Therefore, we could just use a very simple language for declaring such variables or implement support for a limited subset of some well-known schema language. In this alternative, the base model would not be described using this language but rather hard-coded into the front-end.

The back-end modules are responsible for translating the configuration data into configuration file fragments. As regards their implementation, we have two alternatives. The first alternative is to implement them as Lua functions invoked by the framework in a defined way. The framework would provide a library that allows the said functions to access the data model, and also otherwise assists in their implementation. The functions would report the results back to the framework, which finally would translate them into target files.

In the second alternative, the back-end modules would be implemented using a template language rather than a general-purpose programming language. An example of a firewall-related template language is ferm 🔓, which unfortunately is implemented in Perl. Ferm also lacks certain capabilities required to implement e.g. the Zone and Service concepts conveniently. However, we could introduce a new template language that would better suit our purposes. Such a language would eliminate some redundancy from the back-end modules which necessarily comes with the use of a general-purpose language. On the other hand, developing and maintaining such a language would take effort and might make the framework initially more difficult to use.

The back-end will contain functionality for domain name resolution. In the data model, hosts of groups thereof can be identified by their domain names. The back-end will resolve these to IP addresses, which will be stored in the target files, so there will be no need to resolve anything when activating the configuration during boot.

See also