My thoughts on Slackware, life and everything

Category: Rant (Page 1 of 11)

Put your application inside a VPN jail

The premise

Note; political rant with European bias follows. If you don’t want to be exposed to my political views but still want to read the technical content of this article, simply skip the “Premise” and scroll down to “My data under my control”.

Looking at the rapidly deteriorating situation in the United States of America with disgust and shock, my prediction is that the soft approach to opposing Donald Trump’s hostile take-over of the country is going to fail horribly, and will result in the next fascist dictatorship within two years (mark my words).
Therefore I am withdrawing my data from the US based companies as much and as fast as I can. If you live outside the United States, the possibility that US-based companies may just cut-off access to your Cloud data when the Orange Clown instructs them to, is all to real.
It’s not just me; there is a real and irreversible push in the European Union to put an end to the imbalance and invest in a European open-source based Cloud infrastructure to rival the US companies that have gladly received our money for years and still can’t make hard commitments that they won’t apply the kill-switch when the Fascist-in-Chief demands it.

My data under my control

The desire to have more control over your own data is not new of course. Discussions about what that means on a wider scale are simply accelerated by current events.
You can already access a lot of detailed information on how to become independent of the big tech companies via my own series of blog articles called “Slackware Cloud Server“. I am researching two additional installments to that series: one about how to setup Joplin Server as an alternative to OneNote (Joplin can actually import OneNote files easily), and another one about how to setup a cheap-ish remote storage to make safe backups of all your locally stored data. Data to be stored inside Europe of course. More on that in due time.

A necessary step to move away from Google and friends was purchasing a Proton family account. The realization hit me a long while ago of course, that free services like GMail are only free because Google harvests, uses and sells your data that you store on their platform.
Proton on the other hand is a Swiss-based company with a focus on privacy. It costs money to use their services, yes, but the data you store with Proton will be secure and safe from those prying eyes.
If  you have not yet implemented my Slackware Cloud Server, then you are most likely subscribed to one or more Cloud-based streaming services like Netflix, HBO, AppleTV, Disney+ and so on – you pay when you determine you get your money’s worth. So I pay to get my data off Google, Microsoft and Dropbox servers.

VPN as a privacy tool

Looking at the services that come with a Proton account, I noticed that they offer a VPN service as part of the package. This reminded me of the importance to have a proper VPN installed. People who already live inside a dictatorship know that a VPN can be a lifeline to the free world, and my American friends: you will need that VPN too, soon!

I am not in favor of free VPN’s. Speeds are never great and you have no certainty or guarantee that the free VPN provider is not actually harvesting and selling your personal data.
Unless you yourself run the VPN server. At home I implemented an actual Virtual Private Network using Wireguard. WireGuard is a VPN protocol which is part of the Linux kernel and the user-space is a simple binary, controlled by simple configuration files. It connects my family’s laptops, phones and also the network infrastructure of our camper van to our home, combining all devices into a single network with one exit point towards the Internet which is here, at home.
This kind of VPN server is not meant to prevent other parties spying on you. Instead it is the type of VPN that securely connects devices (one server and many roaming clients) into a single ‘local’ network; the traditional interpretation of VPN. All devices inside the network can communicate with each other; this is how I can access my home automation even when I am out of the country in my camper van.

The VPN solution I want to discuss here, is of the other kind: the one that hides your activities from prying eyes. A privacy-enhancing tool.
This kind of VPN connection creates a tunnel between your local computer and one of many remote servers operated by a VPN provider. You can get a subscription from companies like NordVPN, PIA to name a few, or in my case: ProtonVPN. The VPN allows you to ‘go anonymous’ with the click of a button. Whatever information you access on the Internet through a VPN tunnel can never be traced back to you personally because your IP address is effectively hidden and replaced by the IP address of the VPN access point.

Installing the VPN client offered by any of these providers is trivial, applications offered for Linux, Windows, Android and iOS. The standard usage is also well-documented. It becomes more interesting when your use-case is more un-common.

This article shows how you can install a VPN (WireGuard in this case), place the VPN network interface inside a jail so that your Slackware computer does not even know it is there, and then add programs to that jail. The programs inside that network jail will be forced to access the internet through the VPN tunnel, they cannot circumvent the jail and therefore do not have access to your regular network connection. Your privacy-sensitive information will not be able leak out of your regular network connection. These jailed applications will still be able to communicate with local applications and services via the loopback interface.

Intrigued? Read on!

Put the VPN in a network jail

As a Slackware Linux user, text-based configuration files are always preferred over Graphical Users Interfaces, right 🙂

Obtain a WireGuard configuration

I downloaded the WireGuard configuration file that allows me to connect to the Proton VPN service from my own account’s dashboard. There’s documentation on how to do that.
The contents of this configuration file are really simple. All they describe are the characteristics of the two endpoints: yours (using a private key for encryption) and the remote server (identified by a public key and an IP address or hostname). The remote server in turn has a copy of your public key so that they can validate your identity:

PrivateKey = 2QLYsfx89Lpc24iBtZmygieXYwq1WZwPok8joqB/Fys=
Address = 10.2.0.2/32
DNS = 10.2.0.1

[Peer]
PublicKey = dOJQd38biobpWxq4wpF7mk2oUiJnjHZlDZ7s8X/z+xs=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = XXX.XXX.XXX.XXX:51820

The two key values are of course bogus. The “XXX.XXX.XXX.XXX” will be the IP address of the VPN server at the other end of the connection.

Move the Wireguard configuration file to ‘/etc/wireguard/proton0.conf‘.  You could now run the command “wg-quick up proton0” to activate the VPN interface but that has a potentially unwanted side effect if your computer is also a server. The ‘wg-quick‘ command installs a new default route forcing all your external traffic through the VPN tunnel.
If you run network services on that computer then your clients will be in for a world of hurt.

How to prevent that the ‘proton0‘ interface forces itself as the default route?

Tame the beast

To prevent ‘wg-quick‘ from overriding your default route and instead keep your physical network interface as your primary gateway always, you must modify the WireGuard configuration file that you just installed.
By default, wg-quick interprets the line “AllowedIPs = 0.0.0.0/0” as a trigger to automatically install a new default route through the VPN interface.

Modify the Configuration File

Open your configuration file  /etc/wireguard/proton0.conf and add the following line into the [Interface] section. This instructs wg-quick to bring up the interface and set the IP, but not touch the system routing table:

Table = off # This prevents the default route override

Save the file and now bring up the interface (using the name of the configuration file “proton0“as argument, this will also determine the name of the VPN interface):

# wg-quick up proton0

Verify your default route is still going via your physical interface:

# ip route show | grep default

You should see a line like this: default via <your_gateway_ip> dev eth0

Verify the ‘proton0‘ interface is active:

# wg show

And finally, verify that all other services that are running on your computer are still accessible.

Routing traffic through the VPN

Since we have disabled automatic routing, no traffic will go through the VPN by default. The question remains of course… how should I access and use this new VPN network interface?
There are as many ways as there are use-cases, but for the sake of this article we focus on a single use-case.
We want to route specific traffic through the ‘proton0‘ network interface while keeping ‘eth0‘ (or whatever your default network interface is named) as the default for everything else. More specifically, I want to be able to determine which application(s) should access the Internet exclusively via the VPN interface. We can do this and at the same time leave the main system completely untouched; no ‘iptables‘ or ‘fwmark‘ rules are required to create this separation. How?

We are going to use Network Namespaces (netns).

A Network Namespace gives us the power to place the VPN interface into a “jail.” Basically it creates a separate network stack which is isolated from the computer’s regular network stack. Applications launched inside this jail use the VPN, while everything else on your system continues to use the default gateway. Here are the steps to do just that.

  • Configure WireGuard to handle network isolation.
    The only manual modification that we need to make to ‘/etc/wireguard/proton0.conf‘ in order to prevent it from updating the computer’s routing table has already been shown higher up in the article: Add the line
    Table = off
    to the [Interface] section of the configuration file.
  • Create a boot script (since this is Slackware we call it a “rc script”) to create the VPN jail every time the computer boots.
    Save the following bash script as “/etc/rc.d/rc.protonvpn-jail” and make it executable via the command
    chmod +x /etc/rc.d/rc.protonvpn-jail
# --- 8< ---
#!/bin/bash
# Configuration of a VPN "jail"
NS_NAME="vpn_jail"
WG_CONF_PATH="/etc/wireguard/proton0.conf"
WG_IF="proton0"

if [[ $EUID -ne 0 ]]; then
  echo ">> This script must be run as root!"
  exit 1
fi

case "$1" in
  start)
    # Automatically find the IP address assigned by Proton
    echo "Extracting IP from $WG_CONF_PATH..."
    VPN_IP=$(grep -Po '(?<=^Address = )[^, \n]+' "$WG_CONF_PATH")
    echo "Extracting DNS resolver from $WG_CONF_PATH..."
    DNS_IP=$(grep -Po '(?<=^DNS = )[^, \n]+' "$WG_CONF_PATH")

    if [ -z "$VPN_IP" ]; then
      echo ">> Error: Could not find Address in $WG_CONF_PATH"
      exit 1
    fi

    echo "Starting VPN Jail for IP $VPN_IP..."

    # Create the network namespace
    ip netns add $NS_NAME

    # Setup a Kill-Switch (using nftables)
    ip netns exec $NS_NAME nft flush ruleset
    ip netns exec $NS_NAME nft add table inet filter
    ip netns exec $NS_NAME nft add chain inet filter output \
      { type filter hook output priority 0 \; policy drop \; }
    ip netns exec $NS_NAME nft add rule inet filter output oifname "lo" accept
    ip netns exec $NS_NAME nft add rule inet filter output oifname "$WG_IF" accept

    # Bring up WireGuard in the default namespace
    wg-quick up proton0

    # Move the interface into the jail and re-assign the IP (which was lost during move)
    ip link set $WG_IF netns $NS_NAME
    ip netns exec $NS_NAME ip addr add $VPN_IP dev $WG_IF

    # Bring the network link up (don't forget loopback!)
    # and configure the default route inside the jail
    ip netns exec $NS_NAME ip link set lo up
    ip netns exec $NS_NAME ip link set $WG_IF up
    ip netns exec $NS_NAME ip route add default dev $WG_IF

    # Configure a working DNS for the jail namespace
    mkdir -p /etc/netns/$NS_NAME
    echo "nameserver $DNS_IP" > /etc/netns/$NS_NAME/resolv.conf

    echo "VPN Jail is READY. IP: $VPN_IP"
    ;;

  stop)
    echo "Cleaning up VPN Jail..."
    ip netns del $NS_NAME
    # The interface moves back to default namespace on netns delete; shut it down
    wg-quick down proton0 2>/dev/null
    rm -rf /etc/netns/$NS_NAME
    echo "VPN Jail removed."
    ;;

  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac
# --- 8< ---

Let’s quickly run through the script’s “start” section.

  • The script greps for the “Address =” line in our WireGuard configuration which makes it resistant against a future change in VPN provider or when Proton updates your local VPN endpoint IP address.
  • The IP address of the DNS resolver for the VPN connection is parsed in a similar fashion.
  • A new network namespace is created to serve as our VPN jail.
  • When you choose to run an application behind a VPN, you certainly need a “killswitch“.
    The script uses nftables to ensure that you regular network interface is firewalled from the applications that will run inside the jail. All traffic from the application to Internet will be cut as soon as the VPN interface goes down, so that the application is not suddenly exposing your regular Internet IP address to the whole world.
    How the Kill-Switch Works – A nftables rule sets a default “drop” policy for the output chain inside the jail. Then another nftables rule  only allows network traffic to leave either via the loopback interface (lo: for local inter-application communication) or the WireGuard interface (proton0). If the proton0 interface goes down or is deleted, there is no “accept” rule for any other path. Since the jail doesn’t even “see” your physical interface, the application will simply lose connectivity rather than falling back to your real IP.
  • The WireGuard interface is created and then moved into the jail.
  • After the move to the new namespace we re-associate the IP address of the interface that was stripped by the kernel. Moving an interface to a new namespace is like unplugging it from one stack and plugging it into another; the new namespace has no record of what the previous namespace had configured for the interface.
  • Then the script ensures that the interface is up even if it was previously down.
  • A DNS resolver is configured. We create the “resolv.conf” file in a subdirectory called “/etc/netns/vpn_jail“, because the Linux kernel will automatically bind that directory to /etc/ whenever commands are run inside the “vpn_jail” namespace. This ensures that your DNS queries inside the VPN jail are also routed through Proton VPN, preventing DNS leaks on your primary connection. It cannot get safer!

Add the boot script to Slackware

Add these lines to /etc/rc.d/rc.local :

if [ -x /etc/rc.d/rc.protonvpn-jail ]; then
  echo "Starting Proton VPN jail: /etc/rc.d/rc.protonvpn-jail start"
  /etc/rc.d/rc.protonvpn-jail start
fi

And add these following lines to /etc/rc.d/rc.local_shutdown (if that file does not exist yet, just create it and make it executable):

if [ -x /etc/rc.d/rc.protonvpn-jail ]; then
  echo "Stopping Proton VPN jail: /etc/rc.d/rc.protonvpn-jail stop"
  /etc/rc.d/rc.protonvpn-jail stop
fi

Configuring sudo

Our regular user account will be executing the “ip” command to run applications inside the VPN jail. Since usage of the Linux “ip” command is by default restricted to the root user, we need to create  a “sudoers” rule to allow your regular user account to execute it.

And to be able to launch graphical applications from a desktop shortcut without a prompt popping up to ask for your password, we will arrange for passwordless execution.
The danger when doing this carelessly is that the user can gain access to a root shell by abusing the “sudo” privilege elevation. Therefore we implement a secure wrapper that prevents a user from gaining root access via /sbin/ip netns exec.
As root, create a script that explicitly forces the transition back to the original user once inside the namespace. Call the script “/usr/local/bin/netns-proton” and give it the following content:

#!/bin/bash
# Usage: sudo netns-proton [args...]

NAMESPACE="vpn_jail"
COMMAND="$1"

if [ -z "$COMMAND" ]; then
  echo "Usage: $0   [args...]"
  exit 1
fi

# Remove command from argument list,
# leaving only the extra arguments
shift 1

# Execute inside the namespace,
# forcing a drop to the calling user.
# "$SUDO_USER" is an environment variable set by sudo.
/sbin/ip netns exec "$NAMESPACE" /usr/bin/sudo -u "$SUDO_USER" "$COMMAND" "$@"

Then make that script executable while ensuring that only root can edit it:

# chmod 755 /usr/local/bin/netns-proton

Next, configure sudo. Create a new file named “/etc/sudoers.d/vpn_jail” and add the following line (replace your_username with your actual username):

your_username ALL=(ALL) NOPASSWD: /usr/local/bin/netns-proton *
Using the wildcard * allows you to launch any command inside the namespace without a password. You should replace “your_username” with your own login name of course.

And it is safe: if you run “sudo /usr/local/bin/netns-proton bash“, the resulting shell will be restricted to your regular user permissions, even though it is inside the namespace. Your usage of sudo to enter a namespace is restricted to only the “vpn_jail”.

Quick Verification

You could reboot now, but you can also manually run

# /etc/rc.d/rc.protonvpn-jail start

as root, to create the VPN interface and the associated network jail. Then run the following command as your regular user to show the assigned IP inside the jail:

$ sudo /usr/local/bin/netns-proton ip addr show proton0

And finally, verify that the outside world sees a different IP address coming out of the VPN jail than your regular Internet IP address:

$ sudo /usr/local/bin/netns-proton curl http://myip.slackware.nl

Some trivial usage scenarios

You can now manually launch any application inside the VPN jail by prefixing it with the “sudo /usr/local/bin/netns-proton” command.

To run a web browser:

$ sudo /usr/local/bin/netns-proton firefox

To run a bash prompt inside the VPN jail:

$ sudo /usr/local/bin/netns-proton bash

A more complex usage scenario

A typical application you would want to put inside this VPN jail is a torrenting application. We’ll create a desktop shortcut for a VPN-jailed qBittorrent.
You can of course apply the below to any program but a torrent client can be used to demonstrate that the VPN connection actually works.

  • Copy the regular desktop file into your $HOME:
    $ cp -ia /usr/share/applications/org.qbittorrent.qBittorrent.desktop ~/.local/share/applications/
    and create a shortcut to this on your desktop backdrop. Name it “qBittorrent via VPN”. We will edit the copy, not the original:

    • Open the copied desktop file in an ascii editor and change the “Exec =” line into:
      Exec=sudo /usr/local/bin/netns-proton qbittorrent %U
  • Alternatively create a new file on your desktop directly.  Call it “qBittorrent via VPN”. This will create a file “~/.local/share/applications/qBittorrent via VPN.desktop” – then paste the following content into it:
[Desktop Entry]
Categories=Network;FileTransfer;P2P;Qt;
Comment=Launch qBittorrent inside the VPN Jail
# This uses sudo (permitted by the NOPASSWD rule) to exec in the jail
Exec=sudo /usr/local/bin/netns-proton qbittorrent %U
GenericName=BitTorrent client
Comment=Download and share files over BitTorrent
Icon=qbittorrent
MimeType=application/x-bittorrent;x-scheme-handler/magnet;
Name=qBittorrent
Terminal=false
Type=Application
StartupNotify=false
StartupWMClass=qbittorrent
Keywords=bittorrent;torrent;magnet;download;p2p;
SingleMainWindow=true

Depending on the Desktop Environment , you make have to make this desktop file executable to allow for application-startup via a double-click.

Double-clicking the icon will launch the qBittorrent application inside the isolated network namespace. It’s usage is safe because it will communicate through the VPN and is secured by the built-in “kill-switch” against any accidental exposure.

You can verify that your Torrent client accesses the internet via your VPN:
Open https://ipleak.net/ in your browser (no VPN needed), scroll down to “Torrent Address Detection”, copy the Magnet link that appears there into your qBittorrent application and watch the ipleak page for connection confirmation.
Then bring the VPN down via:

# /etc/rc.d/rc.protonvpn-jail stop

and you should see an immediate loss of connectivity for the qBittorrent program.

Summarizing

I hope this helps keeping you safe 🙂

No Kings! Power belongs to the people

To my friends and their friends and family in the USA: stand up against blatant corruption, greed and power grabs. Fight the corrosion of your democracy and the rise of authoritarianism and fascism in the “land of the free”.

I stand with you.

Let me remind you who started the war in Ukraine and how

I am going to spit 77 million people in the face here, and it needs to be done. I am raging. If you live in the USA and do not want to be confronted by my ‘leftist’ or ‘commie’ political views then unsubscribe from this blog and get the fuck out.
Listen carefully. Blatant lies are coming from the Oval office with the intention to destroy an ally.

The war in Ukraine did not start in 2022, and it was not started by Ukraine.

In February of 2014 Russia invaded Ukraine and annexed Crimea. NATO shied away from aiding Ukraine because of a justified fear of escalating the conflict. And in July of 2014, Russians shot down a commercial airplane over eastern Ukraine, killing hundreds of passengers. Hard work of a journalist collective provided the proof which held up in court.

In the years that followed, Russia kept arming and fueling the hatred of separatists in the eastern Ukraine. Why? Possibly because with the occupation of the Donbas, Russia now has control over 40% of Ukraine’s mineral riches. It’s always about the money, right? Or is the hunger for power stronger than greed?

In 2022 Russia invaded Ukraine from multiple fronts. Not because of what the traitor in the Oval office tells you – that  Ukraine started this war because of their request to join NATO – no, that request was sent to NATO in 2002, TWENTY years before Putin started his ‘special operation’. The invasion of Ukraine was ordered by a mad Russian dictator whose pride was hurt when the West kept ignoring him as a serious partner on the world stage.

Remember this account from what happened during those initial days?

This is not what happens if you pre-empt a strike because you fear your opponent. This is brutal sadism, trademark of Russian warfare where the state, not people, is the only thing that counts.

Those of you who put a traitor in the Oval office have made yourselves complicit, not just because you have enabled the autocracy or even dictatorship which is being created in the USA as we speak. But also complicit in the possible destruction of a European country: Ukraine. Your president with his delusions of grandeur will try again to grab Canada, Panama and Greenland and will leave Ukraine defenseless against Russia’s aggression. He does not care about you. He is a narcissist.
Next may be the start of an all-out war in Europe because Putin sees an opportunity. The USA now believes that Russia is not the enemy and Europe is its own enemy. And who the fuck cares about that in the USA?
I don’t understand you assholes who put this conman on a throne. All because you could not tolerate a black woman in the Oval office?
You don’t believe this? The orange guy keeps doing exactly what he has been telling you for years. There’s no reason to believe that he will change all of a sudden.

Fuck you all, maggots.

And indeed, I have disabled comments to this article. Suck it up.

GNU Screen user? How to migrate hardstatus colors to screen5

And no, don’t try to convince me that I should switch to tmux!

I have been using GNU Screen for ages. It’s a convenient and safe way to manage a remote Linux server. Screen enables me to have multiple ‘windows’ available in a terminal, running its processes independently. When I close screen (or when my ssh connection fails), the processes contained in the remote screen session keep running.
It’s how I can compile Chromium for instance – a package compilation can take up to 12 hours. I go to sleep and the next morning I reconnect the screen client to the remote socket of the still running screen daemon and continue as if I was never away.
Yes I know that tmux is supposed to be the successor of screen, but I simply don’t care.

I operate multiple Slackware servers in remote datacenters and run screen sessions over ssh connections. To avoid any confusion about the server that I am executing commands on, I have configured screen to show relevant information in the bottom line. This concept is called “hardstatus” in screen. Here’s an example showing the three active bash prompts, highlighting  that I am currently working in ‘Window 1‘, but it also shows the server’s hostname in green and the local time in blue.

Before typing anything, I first look at the green text to confirm that I am connecting to the right server.

Now, recently Slackware-current upgraded from GNU screen 4 to version 5 and with that, an old compatibility syntax was removed – a syntax that made it easy to define the colors in that status line. But the info page which describes the syntax is probably written for even more stubborn people than me.

It took me a while to get the look and feel of my screen 4.x status line reproduced in screen 5. In fact, I fixed the hardstatus definition only today (after 4 months of barely tolerating the junked colors and finally having enough of it), and I want to share it with you.

This is what defines the status line in my Linux computers with screen 4:

# Tabbed colored hardstatus line:
hardstatus alwayslastline
hardstatus string '%{= Kd} %{= Kd}%-w%{= Kr}[%{= KW}%n %t%{= Kr}]%{= Kd}%+w %-= %{KG} %H%{KW}|%{KY}%101`%{KW}|%D %M %d %Y%{= Kc} %c%{-}'

And this is how the definition had to change for screen 5 in order to show the exact same status line:

# Tabbed colored hardstatus line:
truecolor on
hardstatus off
hardstatus alwayslastline '%{= .;#999999} %{= .;#999999}%-w%{= #ff0000;#999999}[%{= #ffffff;#999999}%n %t%{= #ff0000;#999999}]%{= .;#999999}%+w %-= %{#00ff00;#999999} %H%{#ffffff;#999999}|%{#ffff00;#999999}%101`%{#ffffff;#999999}|%D %M %d %Y%{= #00ffff;#999999} %c%{-}'

In case you are curious about my full ~/.screenrc definition file, you can find it in liveslak: https://git.liveslak.org/liveslak/tree/make_slackware_live.sh?h=1.8.1.2#n2053 – I still have to fix the hardstatus definition there though.

I hope that this helps some of you old guys.
In the comments section below, I won’t tolerate GNU haters, screen haters or other evangelists. Keep it civil.

Cheers, Eric

Authenticators for 2FA

Multi-factor authentication: it is difficult to find high-profile websites these days that allow you to get away with a simple password-based login. It’s a sobering thought to realize how fast your ‘secure’ password can be hacked using sophisticated techniques that go way beyond brute-force cracking.

So, multi-factor authentication has become the rage. When you authenticate yourself, you increase the security of your account by providing multiple ‘factors‘: something you know (a password or PIN code); but also something you have (a cryptographic identification device or a token); and something you are (which could be a biometric quality such as a fingerprint or a face-iD).

When requiring 2 of these factors,  we talk of ‘two-factor authentication’, better known as ‘2FA’. Then, usually these will be the use of a password combined with the string of digits (a token) produced by an authenticator – whether that is a hardware device or a software implementation.

Popular are authenticator apps on smartphones. Google, Apple and Microsoft have their own authenticators which you can find in the respective stores for your smartphone. They are really easy to use and completely interchangeable – every authenticator will generate the exact same code for a website at the same moment in time.
The disadvantage of these authenticators becomes clear when you lose your smartphone… gone are the authentication codes you need to logon to your account! You’ll have to contact customer support to disable your 2FA so that you can access your data again, and then re-enable 2FA using an authenticator on your new phone.

That’s why Authy became so popular: this is an authenticator which stores your 2FA tokens securely in the company’s (Twilio) cloud storage. With Authy, you can authorize another device (smartphone or desktop) to generate the same 2FA codes for you. And as long as you remember the passphrase which encrypts your cloud-stored tokens, you do not need your original phone to authorize a new phone. Really convenient!
Unfortunately, Authy does not offer a way to export your tokens from their app.  It’s total vendor lock-in as it happens so often. And this month, Authy’s Windows and Linux desktop applications stop working, leaving only Android and iOS as supported platforms for your authenticator. On top of that, there was a recent breach of Authy’s cloud storage, leaking 30+ million email addresses associated with Authy accounts. That facilitates phishing attacks of course, but also, when you try to recover your account after the loss of your phone, Authy would first ask for your phone number and then continue granting access to the related account. Security updates to Authy apps on all platforms are now preventing application initialization based on your phone number, but it speaks a clear message: if you cannot fully trust the company providing you with one of two authentication factors, it may be time to switch.
But, the lack of export capability… indeed.

I have been using Authy for a couple of years, precisely because of the convenience it offers in the rare case that you lose (access to) your phone. Now being really pissed about the vendor lock-in, I went to look for an acceptable alternative authenticator. And I found Ente Auth. It is an open source 2FA authenticator, with the option (not mandatory) to create an account at Ente and sync your local 2FA tokens to their cloud server.  The end-to-end encryption used by Ente has been independently audited,  and the app allows you to both import (from other authenticators that are not Authy) as well as export your tokens. Ente’s server offers a read-only version of the authenticator interface which means, after login you can find your 2FA codes in your browser as well.
Switching from Authy to Ente Auth was a slow and painful proces, where I had to disable and re-enable 2FA on many web sites, but now I am ready to use Ente Auth exclusively. I can only highly recommend this app.

What’s more: Ente has also open-sourced its backend server. Ente is first and foremost an open source and secure alternative to Google Photos or iCloud: a place to store your photos and videos. But the authentication backend has been built as a standalone functionality from the start, which allowed the company to build Ente Auth around that backend. By open-sourcing the backend, you can actually have complete control over cloud-storage of your 2FA tokens! An account on ente.io is then not needed, you simply instruct the authenticator app to connect to your own server address.
And as a bonnus, you also get a secure and self-hosted alternative to Google Photos.

If there’s an interest in a follow-up article explaining how to self-host the Ente Auth server backend, let me know in the comments section below.

Have fun! Eric

« Older posts

© 2026 Alien Pastures

Theme by Anders NorenUp ↑