mirror of
https://github.com/hackacad/bastille.git
synced 2025-12-18 16:21:32 +01:00
209 lines
7.1 KiB
ReStructuredText
209 lines
7.1 KiB
ReStructuredText
Network Requirements
|
|
====================
|
|
Here's the scenario. You've installed Bastille at home or in the cloud and want
|
|
to get started putting applications in secure little containers, but how do I
|
|
get these containers on the network?
|
|
|
|
Bastille tries to be flexible about how to network containerized applications.
|
|
Three methods are described here. Consider each options when deciding
|
|
which design work best for your needs. One of the methods works better in the
|
|
cloud while the others are simpler if used in local area networks.
|
|
|
|
**Note: if you are running in the cloud and only have a single public IP you
|
|
may want the Public Network option. See below.**
|
|
|
|
|
|
Local Area Network
|
|
==================
|
|
I will cover the local area network (LAN) method first. This method is simpler
|
|
to get going and works well in a home network (or similar) where adding alias
|
|
IP addresses is no problem.
|
|
|
|
Shared Interface (IP alias)
|
|
---------------------------
|
|
In FreeBSD network interfaces have different names, but look something like
|
|
`em0`, `bge0`, `re0`, etc. On a virtual machine it may be `vtnet0`. You get the
|
|
idea...
|
|
|
|
Bastille allows you to define the interface you want the IP attached to when
|
|
you create it. An example:
|
|
|
|
.. code-block:: shell
|
|
|
|
bastille create alcatraz 12.1-RELEASE 192.168.1.50 em0
|
|
|
|
When the `alcatraz` container is started it will add `192.168.1.50` as an IP
|
|
alias to the `em0` interface. It will then simply be another member of the
|
|
hosts network. Other networked systems (firewall permitting) should be able to
|
|
reach services at that address.
|
|
|
|
This method is the simplest. All you need to know is the name of your network
|
|
interface and a free IP on your current network.
|
|
|
|
Bastille tries to verify that the interface name you provide it is a valid
|
|
interface. It also checks for a valid syntax IP4 or IP6 address.
|
|
|
|
Virtual Network (VNET)
|
|
----------------------
|
|
(Added in 0.6.x) VNET is supported on FreeBSD 12+ only.
|
|
|
|
Virtual Network (VNET) creates a private network interface for a container.
|
|
This includes a unique hardware address. This is required for VPN, DHCP, and
|
|
similar containers.
|
|
|
|
To create a VNET based container use the `-V` option, an IP/netmask and
|
|
external interface.
|
|
|
|
.. code-block:: shell
|
|
|
|
bastille create -V azkaban 12.1-RELEASE 192.168.1.50/24 em0
|
|
|
|
Bastille will automagically create the bridge interface and connect /
|
|
disconnect containers as they are started and stopped. A new interface will be
|
|
created on the host matching the pattern `interface0bridge`. In the example
|
|
here, `em0bridge`.
|
|
|
|
The `em0` interface will be attached to the bridge along with the unique
|
|
container interfaces as they are started and stopped. These interface names
|
|
match the pattern `eXb_bastilleX`. Internally to the containers these
|
|
interfaces are presented as `vnet0`.
|
|
|
|
VNET also requires a custom devfs ruleset. Create the file as needed on the
|
|
host system:
|
|
|
|
.. code-block:: shell
|
|
|
|
## /etc/devfs.rules (NOT .conf)
|
|
|
|
[bastille_vnet=13]
|
|
add path 'bpf*' unhide
|
|
|
|
Lastly, you may want to consider these three `sysctl` values:
|
|
|
|
.. code-block:: shell
|
|
|
|
net.link.bridge.pfil_bridge=0
|
|
net.link.bridge.pfil_onlyip=0
|
|
net.link.bridge.pfil_member=0
|
|
|
|
|
|
Public Network
|
|
==============
|
|
In this section I'll describe how to network containers in a public network
|
|
such as a cloud hosting provider (AWS, digital ocean, vultr, etc)
|
|
|
|
In the public cloud you don't often have access to multiple private IP
|
|
addresses for your virtual machines. This means if you want to create multiple
|
|
containers and assign them all IP addresses, you'll need to create a new
|
|
network.
|
|
|
|
loopback (bastille0)
|
|
--------------------
|
|
What I recommend is creating a cloned loopback interface (`bastille0`) and
|
|
assigning all the containers private (rfc1918) addresses on that interface. The
|
|
setup I develop on and use Bastille day-to-day uses the `10.0.0.0/8` address
|
|
range. I have the ability to use whatever address I want within that range
|
|
because I've created my own private network. The host system then acts as the
|
|
firewall, permitting and denying traffic as needed.
|
|
|
|
I find this setup the most flexible across all types of networks. It can be
|
|
used in public and private networks just the same and it allows me to keep
|
|
containers off the network until I allow access.
|
|
|
|
Having said all that here are instructions I used to configure the network with
|
|
a private loopback interface and system firewall. The system firewall NATs
|
|
traffic out of containers and can selectively redirect traffic into containers
|
|
based on connection ports (ie; 80, 443, etc.)
|
|
|
|
First, create the loopback interface:
|
|
|
|
.. code-block:: shell
|
|
|
|
ishmael ~ # sysrc cloned_interfaces+=lo1
|
|
ishmael ~ # sysrc ifconfig_lo1_name="bastille0"
|
|
ishmael ~ # service netif cloneup
|
|
|
|
Second, enable the firewall:
|
|
|
|
.. code-block:: shell
|
|
|
|
ishmael ~ # sysrc pf_enable="YES"
|
|
|
|
Create the firewall rules:
|
|
|
|
/etc/pf.conf
|
|
------------
|
|
.. code-block:: shell
|
|
|
|
ext_if="vtnet0"
|
|
|
|
set block-policy return
|
|
scrub in on $ext_if all fragment reassemble
|
|
set skip on lo
|
|
|
|
table <jails> persist
|
|
nat on $ext_if from <jails> to any -> ($ext_if)
|
|
|
|
## static rdr example
|
|
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
|
|
|
|
## dynamic rdr anchor (see below)
|
|
rdr-anchor "rdr/*"
|
|
|
|
block in all
|
|
pass out quick modulate state
|
|
antispoof for $ext_if inet
|
|
pass in inet proto tcp from any to any port ssh flags S/SA modulate state
|
|
|
|
# If you are using dynamic rdr also need to ensure that the external port
|
|
# range you are using is open
|
|
# pass in inet proto tcp from any to any port <rdr-start>:<rdr-end>
|
|
|
|
- Make sure to change the `ext_if` variable to match your host system interface.
|
|
- Make sure to include the last line (`port ssh`) or you'll end up locked out.
|
|
|
|
Note: if you have an existing firewall, the key lines for in/out traffic
|
|
to containers are:
|
|
|
|
.. code-block:: shell
|
|
|
|
nat on $ext_if from <jails> to any -> ($ext_if)
|
|
|
|
## static rdr example
|
|
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
|
|
|
|
The `nat` routes traffic from the loopback interface to the external
|
|
interface for outbound access.
|
|
|
|
The `rdr pass ...` will redirect traffic from the host firewall on port X to
|
|
the ip of Container Y. The example shown redirects web traffic (80 & 443) to the
|
|
containers at `10.17.89.45`.
|
|
|
|
## dynamic rdr anchor (see below)
|
|
rdr-anchor "rdr/*"
|
|
|
|
The `rdr-anchor "rdr/*"` enables dynamic rdr rules to be setup using the
|
|
`bastille rdr` command at runtime - eg.
|
|
|
|
bastille rdr <jail> tcp 2001 22 # Redirects tcp port 2001 on host to 22 on jail
|
|
bastille rdr <jail> udp 2053 53 # Same for udp
|
|
bastille rdr <jail> list # List dynamic rdr rules
|
|
bastille rdr <jail> clear # Clear dynamic rdr rules
|
|
|
|
Note that if you are redirecting ports where the host is also listening
|
|
(eg. ssh) you should make sure that the host service is not listening on
|
|
the cloned interface - eg. for ssh set sshd_flags in rc.conf
|
|
|
|
sshd_flags="-o ListenAddress=<hostname>"
|
|
|
|
Finally, start up the firewall:
|
|
|
|
.. code-block:: shell
|
|
|
|
ishmael ~ # service pf restart
|
|
|
|
At this point you'll likely be disconnected from the host. Reconnect the
|
|
ssh session and continue.
|
|
|
|
This step only needs to be done once in order to prepare the host.
|