Chapter 12: Setting Up Vaultwarden as a Password Manager
Password managers are essential to modern use of the internet. A new data breach is announced almost every day with often millions of user account credentials winding up for sale on the Dark Web. All but the most incompetent websites store passwords as hash values in their database. This means that many data breaches do not result in a password compromise as the hacker only gains access to the password hash. You should never count on that protecting you, however, as often the hashes are compromised as well. Purchasers of these data will often use the unhashed username to identify other online accounts and attempt to login using the compromised password for non-breached services. Even without a data breach, many users are lazy and use common patterns in their password, such as the word “password.” Sometimes, users will try to be sneaky and slip in some numbers and special characters but “P@$$w0rd” is only slightly more secure. Personal information, like family member or pet names, is also common and often easy to obtain from a victim. Password managers allow you to create and store complex passwords. These passwords are often impossible to remember, so not even the user knows their password. The benefit is that a dictionary or social engineering attack on a password is next to impossible to achieve (under current computing technology).
Password managers can be broadly categorized as follows:
Type 1: Browsers
Chrome, Edge, Firefox, and their derivatives all include password managers. Although this is very convenient and allows for easy synching across devices (assuming you are logged into your browser), it is a very insecure method. Although the passwords are stored in an encrypted database on your device, the encryption keys are unencrypted and saved in easy to predict locations. This is akin to locking up your house tight but then setting the key under the doormat. Other issues include being locked down to that particular browser and having far fewer utilities for generating passwords.
Type 2: Offline
KeePass is a well-known offline password manager. It's very secure and can be used to generate complex passwords on whichever device it is installed on. The problem with offline password managers is that by being offline, each installation is independent of the others. If you have KeePass on your computer and KeePass on your phone, adding a password to one will not synch across devices without work on your part. Many users put their password database in a cloud platform like DropBox. But once you do that, you're no longer using an offline password manager.
Type 3: Online
Some are free but most have some sort of a per month or per year cost associated with them. Many commercial VPN providers also offer a password manager, either included with the VPN or as an added premium feature. NordPass, for example, is available to NordVPN subscribers for an additional fee. The primary advantage of online password managers is synching across devices. A user can generate a password on their mobile device NordPass app and have it immediately available to use on their computer. The primary disadvantage of online password managers is that you are entrusting your passwords to a third party. Your passwords live on their servers. The providers may or may not have the ability to decrypt your passwords, and their claims may or may not be trustworthy. To use our house example again, using an online password manager is perhaps similar to paying someone to follow you around and carry your keys. They might not ever copy your keys when you aren't looking. They might not ever use your keys to get into your house. But you're still trusting them with your housekeys. If you could carry them on your person instead, wouldn't that be better?
Before moving on, let's specifically address Apple. Apple devices come with a password manager called iCloud Keychain. It's associated with your iCloud account and so would be considered an online password manager. Although the iCloud Keychain password database is stored in the AES 256-bit inner vault, much of the rest of iCloud's data is encrypted to 128-bits. End-to-end encryption is available but must be specifically enabled. Apple should be commended for offering a very easy-to-use encrypted cloud platform that benefits the many non-technically sophisticated Apple users who would otherwise not be benefiting from encrypted storage. It does further lock in users to the Apple ecosystem and creates a single point of failure should a compromise occur. Apple users, even those using iCloud Keychain, could still benefit from self-hosting their data.
We're going to be creating a solution that is the best of all of all three of the password manager types by self-hosting a password manager. The password manager will work in our chosen browser as a browser extension. We will own all of the data and have it reside on a device that we control, like an offline password manager. But, it will synch across all of our devices, just like an online password manager. The way we'll do this is by installing a version of Bitwarden designed for Docker called Vaultwarden.
A docker-compose.yml file can be very short or very long. There are many optional parameters that we can specify. We're going to keep it simple. Here are some of the parameters we're going to set:
- Name: Best to keep it simple with just the name of the service. In our case, we'll go with “vaultwarden.”
- Image: This is the executable file used to create the container. You choose a specific image to use and Docker builds the container per the specifications of the image. The most recent image available is tagged with “latest.” We'll be downloading and using the “vaultwarden/server:latest” image.
- Restart policy: By default, Docker containers do not restart if the Docker service is terminated. If you reboot your Pi, your Vaultwarden instance will not be available until you launch it with a command line argument. We're going to set it to “always” so that it will launch itself whenever the Docker service starts up.
- Ports: We need to specify two port settings, each associated with an IP address. Before addressing the IP address, let's talk about the ports. The first port after the IP address is the port on the Pi. We're going to go with 8080 in this example. The second port is the port within the container. 8080:80 means that port 80 in the container is going to be mapped to port 8080 on the Pi. In hardware terms, think of it like two switches with an ethernet cable connecting them. One end is plugged into port 8080 on one switch and the other is plugged into port 80 on the other switch. This is a major distinction between traditional software and a container. As a sort-of “mini OS,” the container has all 2^16 number of ports available to itself. Port 80 is still HTTP and we need an HTTP port for the web interface. We're binding port 80 on the container to the Raspberry Pi's port 8080. Essentially we're saying “Access the container's port 80 through the Pi's port 8080.” We do the same with port 3012 which is used for WebSocket support.
- Now let's address the IP address before each port setting. This is the address or address range in which the port binding referred to above will take place. There are many possibilities, but here are the two we will concern ourselves with:
- 127.0.0.1: This is a “loopback” IP address, used by a computer to refer to itself. In this case, we're binding the ports to the Raspberry Pi. Only a request originating from the Pi itself will allow data to be passed between the Pi and the container. This is the right approach if you are exposing your Vaultwarden to the internet. Vaultwarden will be behind a reverse proxy, so all outside communication with the container will be proxied through the Pi. No external connections will be allowed in.
- 0.0.0.0: This is the “wildcard” IP and allows connections from anywhere. You could get more granular and define only access to the local IP range, but as this will only be used without a reverse proxy, i.e., without Vaultwarden exposed to the internet, that's not necessary. As it will exist only on the local network to begin with, the only way to access it remotely is via a VPN. Although on the local network, the client device's communication is not being channeled through a reverse proxy. As a result, we have to allow for external connections and using 0.0.0.0 is a catchall. By all means, if you go this route, change it to your local IP range later but be ready to troubleshoot.
- Volumes: The container is the software. The volume is the data. In this case, all of the passwords will be stored (encrypted) in the directory specified as the volume. Unlike with a VM, the container volume is located on and accessible by the host machine. You can delete the container but so long as the volume remains, a rebuild will have access to all of the same data.
Two key parameters we are not setting:
- Database: Bitwarden uses a SQLite database by default. For personal use, this is perfectly fine. You can specify a more robust database, like MariaDB. Even for a family or small office, SQLite suffices. Vaultwarden can be scaled to a larger office or even an enterprise, in which case you would define a separate database, but we're not worrying about that here.
- Network: True to the term “container,” applications running within a container do not have the ability to communicate outside of the container unless networking has been enabled. Containers speak to each other through what's called a bridge. In addition to containers and volumes, Docker then also has bridges as another layer of abstraction. Without specifying networking options, Docker adds containers to the default “bridge” network. That is fine for our use case so we won't adjust it. You could theoretically disable all networking to the container, but we won't do that in this case.
With all of that explained, we're finally ready to install Vaultwarden. Once it is installed, we'll test it, enable the Admin panel, and prepare it for local access only, should that be our use case.
Step 1: Download and Build Container
- Get the latest image of Vaultwarden from the Docker database:
docker pull vaultwarden/server:latest - In your home directory, create a new directory for your Vaultwarden docker-compose file:
mkdir ~/vaultwarden - Create docker-compose.yml in nano:
nano ~/vaultwarden/docker-compose.yml - Copy and paste the contents below:
version: '3.7'
services:
bitwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "0.0.0.0:8080:80"
- "0.0.0.0:3012:3012"
volumes:
- ./bw-data/:/data/ - Save and exit with
ctrl+X. - Change to the vaultwarden directory, if not already in it:
cd ~/vaultwarden - Run the following command to build the container:
docker-compose up -d
The-dor--detachflag builds the container in the background. Without it, your terminal session will be taken over by the container. - After a minute or two, try to access the web interface. In your browser, go to your Raspberry Pi's IP address and the first port you specified. For example, if your Pi is 192.168.8.2 and you used port 8080, as per the example, you would navigate to http://192.168.8.2:8080.
- You may need to temporarily open a port with
sudo ufw allow 8080 comment ‘vaultwarden', but once fully configured, you can delete this rule.
Step 2: Enable the Admin Panel
- Within the Vaultwarden container is a mini version of Linux. We're going to “SSH” into it and run a command to generate an admin token. We'll use this token to login to the administrator section of our Vaultwarden instance. First, generate a hashed pseudorandom string of characters to act as our admin token.
docker exec -it <container name> /vaultwarden hash
- Set a strong password and enter it twice. It could be the password you plan on using for your Vaultwarden account.
- Copy the output of the hash to your clipboard data.
- Create a file called .env in the ~/vaultwarden directory
nano .env
- Paste the hash output and prepend it with a variable name, like the following:
VAULTWARDEN_ADMIN_TOKEN=<argon token surrounded by single quotes>
- Save and exit with
ctrl+X. - In the docker-compose.yml configurations below, note the new field for an environment variable.
Step 3, Option 1: VPN Only
- We need to generate a self-signed SSL certificate that our browser will use to authenticate the HTTPS session. Create a subdirectory in your vaultwarden directory to house the certificate files and then change into that directory.
mkdir ~/vaultwarden/certscd ~/vaultwarden/certs
- Run this command to generate a self-signed certificate:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=<Pi IP>"
- With our self-signed certificate, we now adjust our docker-compose.yml. Copy and paste the below:
version: '3.7'
services:
bitwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "0.0.0.0:8080:80"
- "0.0.0.0:3012:3012"
volumes:
- ./bw-data/:/data
- ./certs/cert.pem:/cert.pem:ro
- ./certs/key.pem:/key.pem:ro
environment:
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}
- ROCKET_TLS={certs="/cert.pem",key="/key.pem"}
Step 3, Option 2: Domain Name
- Ensure you have a valid DNS A record pointing to your public IP address.
- Update the docker-compose.yml to the following:
version: '3.7'
services:
bitwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:3012:3012"
volumes:
- ./bw-data/:/data/
environment:
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} - Before we can access Vaultwarden, we need to put it behind a reverse proxy. Skip to the next chapter and add routing for your Vaultwarden domain.
- Having set up the reverse proxy, your Vaultwarden instance is now accessible by whatever domain you set with your DNS record.
Step 4: Create an Account and Enable 2FA
- Whether via a local IP address or a domain name, navigate to your instance.
- Create an account. You need to provide an email address as a username. It's just a username and doesn't have to be a real email address. You may in fact want to not use your primary email address as someone trying to break in would now also need to figure out your username in addition to your password.
- Set a very, very strong password, particularly if you went with the domain name option. This is final layer of protection between you and all of your passwords. If there's one extremely complex 20+ character password that you can remember, this would be the place for it.
- Once logged in, go the settings menu in the top right and then security. Note the two-factor authentication options available. At the very least, select an authenticator app option. Consider using a hardware token like a Yubikey, if you have one.
- To access the admin panel, append /admin to the end of the URL. It will ask for your admin token. Enter the password you set when you created the argon hash in Step 2. There are a lot of settings here, so take some time to explore some of the options, both in the admin panel and the normal user settings.
Step 5: Download Mobile Apps and Browser Extensions
Vaultwarden is a Docker-specific implementation of Bitwarden. When downloading apps and extensions, you'll search for Bitwarden rather than Vaultwarden. All of the major browsers have Bitwarden extensions that will allow you to save and fill in passwords as if using a browser password manager. Both Android and iOS have Bitwarden apps. When opening them for the first time, select a custom server and put in the URL for your instance.
With all of the above accomplished, you now have a secure password manager, accessible anywhere in the world. Unlike a commercial password manager, you own all of your data. The consequences of this approach are that should your Raspberry Pi get corrupted or go offline, all of your passwords will be lost. If you haven't begun to take backup images of your SD card, now is the time to start. If you ever need to rollback a Vaultwarden-breaking change, you'll be able to quickly reconstitute your password manager.
In the next chapter, we're going to have our Pi act as a reverse proxy server. For those who went with the domain name route, you will have already skipped ahead to this chapter.
