Introduction

All articles here are based on the creation of a jail, as I always run each application in its own environment. This ensures clean requirements and no unnecessary mutual dependencies. Jails can run services very simply, leanly and securely. For FreeBSD, it doesn't matter whether one or 100 jails are running at the same time, only the services running in them are relevant. This also makes the whole thing very efficient.

Goals

The goal ist the creation of a jail with the most important basic settings so that other articles can build on it. Important: These instructions have been explicitly designed to run in coexistence with BHYVE on a FreeBSD Server. This means that the storage of the data and the network interfaces are configured in such a way that both are based on the same logic.

NEW: For the very impatient I have a console only section. There are only commands, no explanations.

Last update:

Basic requirements

  • A FreeBSD server is set up and prepared
  • The jails are stored in the following ZFS pool: work
  • OPTIONAL: The data of the jails are stored in the ZFS pool work in the dataset bastille, which is then integrated under /usr/local/bastille/data
  • Network card of the host system with access to the LAN network: igb0

FreeBSD

Netzwerk

Jails can either get their own IP address from the same LAN network as the host system via DHCP or are operated with an IP address in a private address range on the host. Access is then permitted via pf or the NAT. Two new interfaces are created for this purpose:

  • localnet0 = Private network only on the host. The host itself has the IP address 10.0.0.1.
  • publicnet0 = Bridge to the local network together with the igb0 interface

This is prepared in /etc/rc.conf:

sysrc cloned_interfaces="bridge0 lo1"       # Creates new interfaces with the names bridge0 and lo1
sysrc ifconfig_bridge0_name="publicnet0"    # bridge0 is renamed to publicnet0
sysrc ifconfig_lo1_name="localnet0"         # lo1 is renamed to localnet0
sysrc ifconfig_publicnet0="addm igb0 up"    # igb0 is added to the network bridge
sysrc ifconfig_localnet0="inet 10.0.0.1/24" # Gateway address for localnet0
service gateway enable                      # The IP routing function of FreeBSD is activated

The customizations are activated with service netif restart and are visible via ifconfig:

publicnet0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
    options=0
    ether 68:9d:1c:13:a9:1d
    id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
    maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
    root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
    member: igb0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
            ifmaxaddr 0 port 1 priority 128 path cost 55
    groups: bridge
    nd6 options=9<PERFORMNUD,IFDISABLED>
localnet0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
    options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    inet 10.0.0.1 netmask 0xffffff00
    inet6 fe80::1%localnet0 prefixlen 64 scopeid 0x6
    groups: lo
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

BastilleBSD

Install

BastilleBSD is quickly installed after adapting the package source with pkg install -y bastille.

Customise

With service bastille enable BastilleBSD starts automatically on boot, but with these entries in /etc/rc.conf it is only complete:

sysrc bastille_list= # A list of the jails that should be started automatically at boot time

The following entries are adjusted in the configuration file /usr/local/etc/bastille/bastille.conf:

sysrc -f /usr/local/etc/bastille/bastille.conf bastille_tzdata="Europe/Berlin" # Set time zone
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_enable="YES"       # Activate ZFS functions
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_zpool="work"       # ZFS Pool 
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_prefix="bastille"  # Bastille directoy Prefix
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_network_loopback="localnet0" # Network interface for private jails
bastille setup pf # Copy basic firewall rules
service pf enable # Activation of the pf firewall
service pf start  # Start the firewall, the SSH connection may be interrupted in the process
bastille bootstrap 14.1-RELEASE update # Download and unpack the latest FreeBSD Version

The pf rules created then only allow a connection via SSH on port 22 on the host. Ping is not permitted. Adjustments must then be made manually in /etc/pf.conf.

A pass in inet proto icmp as a new line in /etc/pf.conf, for example, allows ping again.

The directory structure per zfs list then looks like this:

NAME                                  USED  AVAIL  REFER  MOUNTPOINT
work/bastille                         651M   430G   136K  /usr/local/bastille
work/bastille/backups                  96K   430G    96K  /usr/local/bastille/backups
work/bastille/cache                   199M   430G    96K  /usr/local/bastille/cache
work/bastille/cache/14.1-RELEASE      199M   430G   199M  /usr/local/bastille/cache/14.1-RELEASE
work/bastille/jails                    96K   430G    96K  /usr/local/bastille/jails
work/bastille/releases                452M   430G    96K  /usr/local/bastille/releases
work/bastille/releases/14.1-RELEASE   451M   430G   451M  /usr/local/bastille/releases/14.1-RELEASE
work/bastille/templates                96K   430G    96K  /usr/local/bastille/templates

Before continuing, now is a good time to restart the system with reboot to see if everything is still working.

  • [ ] The interfaces
    • [ ] publicnet0 with member igb0 and
    • [ ] localnet0 with IP Address 10.0.0.1
  • [ ] Routing is activated, because sysctl net.inet.ip.forwarding has got the value 1
  • [ ] work/bastille mounted to /usr/local/bastille The preparations are now complete and the system is ready.

Creating

Jails can now be created in two ways

  • bastille create JAILNAME 14.1-RELEASE 10.0.0.2 localnet0 creates a jail with the private network. The jail is initially not accessible from the local network, the required ports are later released via NAT in the pf firewall (as with Docker)
  • bastille create -B JAILNAME 14.1-RELEASE 0.0.0.0 publicnet0 creates a jail which obtains an IP address from the local network via DHCP and is also fully accessible via it

It is best to store the IP address statically in the DHCP server so that it no longer changes and publish it via DNS (JAILNAME.domain.local).

Konsole

sysrc cloned_interfaces="bridge0 lo1"
sysrc ifconfig_bridge0_name="publicnet0"
sysrc ifconfig_lo1_name="localnet0"
sysrc ifconfig_publicnet0="addm igb0 up"
sysrc ifconfig_localnet0="inet 10.0.0.1/24"
service gateway enable
service netif restart
pkg install -y bastille
sysrc bastille_list=
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_tzdata="Europe/Berlin"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_enable="YES"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_zpool="work"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_prefix="bastille"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_network_loopback="localnet0"
bastille setup pf
service pf enable
service pf start
bastille bootSchnittstellen undstrap 14.1-RELEASE update
bastille create JAILNAME 14.1-RELEASE 10.0.0.2 localnet0    # Localnet jail or 
bastille create -B JAILNAME 14.1-RELEASE 0.0.0.0 publicnet0 # DHCP jail
bastille start JAILNAME

Voilá