1. Tunneling Elixir Cluster Network Traffic Over Wireguard

    Tue 07 November 2023

    Introduction

    The other day I was supporting a customer with an Elixir-based platform that would make use of Elixir libcluster, so messages on one host can be passed to other hosts. This can - for example - enable live updates for all users, even if they are not communicating with the same application server.

    Encryption

    Elixir's libcluster does support encrypted communication using TLS certificates however I was struggling with the help of an application developer to make it work.

    "severity":"warn","message":"[libcluster:example] unable to connect to :\"app@Host-B\"
    

    I'm absolutely open to the idea that we did something wrong and certificate-based encryption will work, but we were time-constrained and we decided to opt for another solution that seemed simpler and easier to maintain.

    Wireguard as the encrypted transport

    I deployed a Wireguard mesh network between all application servers using Ansible, which was straight forward. We just provisioned all hosts into the /etc/hosts file to keep things simple.

    In the table below, we show a simplified example of the setup.

    Hostname IP-address Wireguard Hostname Wireguard IP-address
    Host-A 10.0.10.123 Host-A-wg 192.168.0.1
    Host-B 10.0.11.231 Host-B-wg 192.168.0.2

    The Elixir applications would only know about the Host-A|B-wg hostnames and thus communicate over the encrypted VPN tunnel.

    The problem with wireguard and libcluster

    The key issue with libcluster is that when Host-A connects to Host-B, it uses the DNS hostname Host-B-wg hostname. But the actual hostname of Host-B is - you guess it: 'Host-B'. This means there is a mismatch and for reasons unknown to me, the libcluster connection will fail.

    So the target hostname as configured in libcluster must match the hostname of the actual host! Since libcluster seems to make usage of domain names mandatatory, using IP-addresses was not an option.

    If we would point Host-B to it's Wireguard IP-address (192.168.0.2), the problem would be solved. However, in that case, Wireguard doesn't know about the external 10.0.11.231 IP address and also tries to connect to the non-existing 192.168.0.2 address. So the Wireguard tunnel would never be created.

    The solution

    The solution is not that elegant, but it works. We still point the Host-B domain name to the wireguard IP address of 192.168.0.2 but we create an additional DNS record specifically for Wireguard, pointing to 10.0.1.231, so it can setup the VPN tunnel.

    This is what /etc/hosts looks like on Host-A:

    10.0.10.123 Host-A
    192.168.0.2 Host-B
    10.0.11.231 Host-B-wg
    

    And this is what /etc/hosts looks like on Host-B:

    10.0.11.231 Host-B
    192.168.0.1 Host-A
    10.0.10.123 Host-A-wg
    

    Evaluation

    Although all choices are a tradeoff, for us, the Wireguard-based solution makes most sense. Especially now that we have an encrypted tunnel between all hosts and any future communication between hosts can thus be encrypted without any additional effort.

    Tagged as : Uncategorized
    If you have any comments email me, see the About page for contact details.
  2. LFS - Linux Firewall Script Released

    Tue 28 December 2010

    I started a small new Google project for a new script I wrote called LFS. It stands for Linux Firewall Script.

    I run a small Linux box as an internet router that doubles as a firewall. The firewall is configured using iptables. In my opinion, iptables is not the easiest tool to use and may have a steep learning curve for people new to it.

    The goal of LFS is to provide an easier interface to iptables. It also adds some features that by default are not or difficult to setup using only iptables. The most important additional feature is the use of objects and groups. Object groups can be used to make a single rule affect multiple hosts, networks or services.

    LFS uses a single configuration file which contains the firewall rules. Rules look like this:

    nat 192.168.1.0/24 88.32.44.144 eth0
    port_forward 88.32.44.144 192.158.1.10 80/tcp 8080/tcp
    

    Or by using variables:

    nat "$INTERNAL_NETWORK" "$EXTERNAL_IP" "$NAT_INTERFACE"
    port_forward "$EXTERNAL_IP"  "$INTERNAL_HTTP_SERVER" "80/tcp" "8080/tcp"
    

    Please visit the project page for some examples.

    Tagged as : Uncategorized
    If you have any comments email me, see the About page for contact details.

Page 2 / 34