Run Your Own LastPass on Hardened OpenBSD
With LastPass having suffered yet another data breach – important update here – it’s probably time to take matters into your own hands and run your own cloud password manager. Let’s do exactly that, on a hardened OpenBSD system!
Update 2022-12-22: Turns out attackers were in fact able to gain access to customer’s encrypted vaults on LastPass. Check the comments on Hacker News.
As humans our brains are naturally programmed to be very selective of the information they absorb. With the millions of messages the brain receives at any given time, it is obvious that substantial filtering is required in order for us to be able to function. Even when we pay close attention to something it might well be that details won’t stick for long. We can all agree that things that we can relate to or that make sense to us are easier to remember than those that do not, without going into great detail about how “working memory” functions or how synapses are generated and strengthened. For example we use vanity phone numbers – that is a phone number like 1-800-GoFedEx – because it’s easier for us to remember them over a random sequence of numbers that we can’t relate to. Ask yourself in two hours What’s FedEx’ phone number? and you’ll likely be able to tell.
Relatability and thereby rememberability is also the reason why 123456
,
password
, monkey
and trustno1
are amongst the most common
passwords, even when something like
VMemL9U7Vx5dBtrSsNfyn3Sq
would be a more sensible choice. For the average Joe
it would be pretty much impossible to come up with a password like that and
instantly remember it. Heck, I can barely remember the Punycode of
my own domain that I’ve been using for several years now.
To help with this, password managers have been on the rise over the past decade or so. Password managers intend to replace the PostIt notes on people’s computer monitors and allow for complex passwords without the hassle of remembering them or writing them down in various places. It’s basically an encrypted database that uses a single master password to encrypt all other passwords with. Ideally the master password is the only complex password a user has to remember, in order to unlock the password manager and allow it to automatically fill login forms with previously saved account info.
To make the passwords database available across every device, password managers usually offer a paid cloud service for syncing. Like every cloud service, password managers have to work tirelessly to protect their users’ data from malicious actors. Unfortunately snafus still happen from time to time, which in some cases could lead to actual user data being accessed by others. Of course, password databases are encrypted, and with a strong enough password there’s little chance for individual actors to actually crack open a database. Yet even just the theoretical possibility of this happening begs the question: Are the features that we’re getting from services like 1Password, LastPass and others really worth the risk? Wouldn’t we be better off hosting our own password manager cloud, that is somewhat less in the spotlight of attackers or might not even be accessible to them in first place?
“But that’s awfully complicated and probably requires developing all the nifty clients that 1Password, LastPass and others already have!” you might say. Well, it turns out, everything we need is already there, as beautiful open source software.
Let’s have a look at how we can set up all the bits and pieces to run our own password manager cloud on OpenBSD, using the open source password manager Bitwarden – but with a twist!
Options
I’m going to go through two different options here:
- A bare metal setup, in this case on a Raspberry Pi 4B
- A cloud instance, in this case on Vultr
The installation differs depending on where you choose to set this up. For the bare metal option installation of the base OpenBSD system might be different for your hardware. In case you should be going for a cloud instance, I’d recommend making it solely available through a VPN for enhanced protection.
Option A: Bare metal (Raspberry Pi)
First things first: Make sure your Raspberry runs the latest firmware version.
If it doesn’t, flash Raspberry Pi OS on a microSD card, run
it and use the rpi-update
and rpi-eeprom-update
commands to update the
device.
Next, download the latest OpenBSD arm64 images (7.2 in this
case), flash the miniroot72.img
onto a microSD card, and install72.img
onto
an USB stick and plug both into the Raspberry Pi. Connect the device to a
display, attach a keyboard and connect power to start it. As soon as you can see
the boot>
prompt, type in set tty fb0
and hit enter. The installation should
start.
Hint: Sometimes it might be needed to press random keys on the keyboard for procedures to continue.
Option B: Cloud instance
If you’re going to use a cloud instance for this, there’s not much you need to do apart from launching a new compute instance with the latest OpenBSD image available. However, if you’re looking forward to have the instance drive encrypted, you will need to install a new compute instance using the official OpenBSD install image. For installation details, please continue below.
(Optional) Hard Drive Encryption
Our passwords database in itself is already going to be encrypted, meaning that you don’t necessarily need an extra layer of at-rest encryption. However, if it lets you sleep better to know that even in case an adversary would rip the hard drive out of your device it wouldn’t be much benefit to them (for the foreseeable future), then this part is for you.
Remember though that with hard drive encryption you will have to enter the passphrase every time the device/server boots. This means that for something like a Raspberry Pi you’ll need to have a keyboard and ideally a display attached – or a KMV – and for cloud instances you’ll have to connect to it via VNC on every reboot to enter the passphrase. The latter option might not be ideal as you probably can’t tell for sure whether the connection is sufficiently secure for you to send your encryption passphrase through it. For physical hardware you could always switch to a certificate on an USB stick or a YubiKey, to avoid attaching a keyboard/display every time it requires a reboot.
Let’s quickly go over how to install OpenBSD with hard drive encryption turned on:
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? s
First, find out block device(s):
# dmesg | grep -i block
It’s usually something like sd0
. Next, add the device for it under /dev
:
# cd /dev
# sh MAKEDEV sd0
Continue by writing the MBR boot code, then create a partition layout and add an encrypted device:
# fdisk -iy sd0
# disklabel -E sd0
sd0> a a
offset: 64
size: *
FS type: RAID
sd0*> w
sd0> q
# bioctl -c C -l sd0a softraid0
# cd /dev
# sh MAKEDEV sd1
# dd if=/dev/zero of=/dev/rsd1c bs=1m count=1
# exit
Next we’re going to install OpenBSD as we usually would. Adjust the values (hostname, username, network interfaces, …) to your needs. Values in square brackets are default values. If there’s no other value behind them it means we can press the enter key to accept the default:
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? i
Choose your keyboard layout ('?' or 'L' for list) [default]
System hostname? (short form, e.g. 'foo') v4u1t
(for bare metal could be) Available network interfaces are bse0 bwfm0.
(for cloud instances usually) Available network interfaces are vio0 vlan0.
Which network interface do you wish to configure? (or 'done') [bse0]
IPv4 address for bse0? (or 'autoconf' or 'none') [autoconf]
IPv6 address for bse0? (or 'autoconf' or 'none') [none] autoconf
(for bare metal could be) Available network interfaces are bse0 bwfm0.
(for cloud instances usually) Available network interfaces are vio0 vlan0.
Which network interface do you wish to configure? (or 'done') [done]
Password for root account? (will not echo)
Password for root account? (again)
Start sshd(8) by default? [yes]
Do you expect to run the X Window System? [yes] no
Setup a user? (enter a lower-case loginname, or 'no') [no] mrus
Full name for user mrus [mrus]
Password for user mrus? (will not echo)
Password for user mrus? (again)
Allow root ssh login? (yes, no, prohibit-password) [no]
What timezone are you in? ('?' for list) [US/East]
Available disks are: sd0 sd1.
Which disk is the root disk? ('?' for details) [sd0] sd1
No valid MBR or GPT.
Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [whole]
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a]
Available disks are sd0.
Which disk do you wish to initialize? (or 'done') [done]
Location of sets? (cd0 disk http nfs or 'done') [cd0]
Pathname to the sets? (or 'done') [7.2/amd64]
Set name(s)? (or 'abort' or 'done') [done] -game* -x*
Directory does not contain SHA256.sig. Continue without verification? [no] yes
Location of sets? (cd0 disk http nfs or 'done') [done]
Exit to (S)hell, (H)alt or (R)eboot? [reboot]
Voilà! Your device/cloud instance now runs from an encrypted drive.
First Boot
As usual when booting OpenBSD for the first time, let’s take care of a few basics:
v4u1t# mail
v4u1t# man afterboot
On actual hardware you might want to check date
and see what time it is. In
case it seems off we can correct it right away:
v4u1t# ntpctl -sa
v4u1t# rdate -ncv time.google.com
Additionally I’ve changed the mirror that OpenBSD was using to a different one, since I was having issues with the default one lately:
v4u1t# cat /etc/installurl
https://ftp.eu.openbsd.org/pub/OpenBSD
Next, perform a system upgrade to -current
. We want this because -stable
releases especially for the password manager are outdated.
v4u1t# sysupgrade -s
The system will reboot – don’t forget to enter your passphrase in case you
enabled drive encryption! – and on the next login you should be greeted with a
version that says -current
:
OpenBSD 7.2-current (GENERIC.MP) #1917: Thu Dec 8 15:24:02 MST 2022
Next install a set of handy tools:
v4u1t# pkg_add zsh neovim mosh rsync git login_oath py3-pyqrcode lynis
v4u1t# ln -s /usr/local/bin/nvim /usr/local/bin/vim
v4u1t# chsh -s /usr/local/bin/zsh root
v4u1t# chsh -s /usr/local/bin/zsh mrus
Hint: Changing vim to nvim or the default shell to
zsh
is personal preference and nothing that’s actually required.
Now continue by setting up an enhanced login procedure for our system user(s).
Public Key + TOTP + Password Authentication
Add the following configuration to the very end of /etc/login.conf
:
totp:\
:auth=-totp-and-pwd:\
:tc=default:
In a second shell, connect via SSH as your user – mrus
in my case – and
create a TOTP key:
v4u1t% openssl rand -hex 20 > ~/.totp-key
v4u1t% chmod 400 ~/.totp-key
v4u1t% python3 -c "import pyqrcode;\
import binascii;\
import base64;\
f = open('.totp-key');\
key = f.read();\
f.close();\
qr = pyqrcode.create('otpauth://totp/"$USER"?secret='+\
base64.b32encode(binascii.unhexlify(key.rstrip('\00\n'))).decode('utf-8')+\
'&issuer=v4u1t');\
print(qr.terminal(quiet_zone=1));"
The QR code can be scanned with virtually any TOTP app on a phone and it’ll start generating one-time tokens, that we’ll use to log in on the system from now on.
Copy the local SSH public key from your computer (usually cat ~/.ssh/id_*.pub | wl-copy
) and add it to your user on OpenBSD:
v4u1t% vim ~/.ssh/authorized_keys
Back in the root shell, add your user to the totp
login class:
v4u1t# usermod -L totp mrus
And update the /etc/ssh/sshd_config
:
Port 31231
Protocol 2
Compression no
LogLevel VERBOSE
ClientAliveInterval 180
ClientAliveCountMax 2
TCPKeepAlive no
LoginGraceTime 30
MaxAuthTries 2
MaxSessions 2
AllowUsers mrus
PermitRootLogin no
PermitEmptyPasswords no
PasswordAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
AuthenticationMethods publickey,password
ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no
X11Forwarding no
PermitUserEnvironment no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
GatewayPorts no
PrintMotd no
PrintLastLog yes
Important: Adjust the value of
AllowUsers
!
While we’re at it, let’s also change the Port
to a number greater than 1024,
e.g. 31231
.
Before you do anything else, run rcctl restart sshd
, open a third shell and
test logging in with your user. Your SSH client will need to supply an SSH key
and you will be asked to enter a password, for which you have to enter the
TOTP token, followed by a /
and then your password, e.g.
123456/mypassword123!
.
If the login works you’re good to go. If not, double check every step until here and make sure you didn’t forget anything. Make sure to stay connected via SSH until you figured it out, otherwise you won’t be able to log back in again!
SSL
Let’s take care of the SSL certificate that we’ll be using to secure client connections with. If you’ve opted for the bare metal setup, we will create our own CA and use a self-signed certificate, for which we’ll install the intermediary certificate on our client devices. If you went for the cloud instance, we’re going to use a Let’s Encrypt certificate.
Option A: Own CA + Self-Signed Certificate
Start by installing HashiCorp Vault and jq
:
v4u1t# pkg_add vault jq
Open the configuration file under /etc/vault/vault.hcl
and set the node_id
– for example to the machine’s hostname. Then start Vault using rcctl enable vault && rcctl start vault
.
Before we use Vault, we need to initialize it once:
v4u1t# export VAULT_ADDR='http://127.0.0.1:8200'
v4u1t# vault operator init
Copy the output of this command and temporarily store it in a secure location. To understand what this is about, let’s have a look at the Vault documentation:
Initialization outputs two incredibly important pieces of information: the unseal keys and the initial root token. This is the only time ever that all of this data is known by Vault, and also the only time that the unseal keys should ever be so close together.
For the purpose of this getting started tutorial, save all of these keys somewhere, and continue. In a real deployment scenario, you would never save these keys together. Instead, you would likely use Vault’s PGP and Keybase.io support to encrypt each of these keys with the users’ PGP keys. This prevents one single person from having all the unseal keys. Please see the documentation on using PGP, GPG, and Keybase for more information.
Every initialized Vault server starts in the sealed state. From the configuration, Vault can access the physical storage, but it can’t read any of it because it doesn’t know how to decrypt it. The process of teaching Vault how to decrypt the data is known as unsealing the Vault.
Unsealing has to happen every time Vault starts. It can be done via the API and via the command line. To unseal the Vault, you must have the threshold number of unseal keys. In the output above, notice that the “key threshold” is 3. This means that to unseal the Vault, you need 3 of the 5 keys that were generated.
Continue by unsealing Vault. To do so, we need to run the following command three times, entering a different unseal key each time:
v4u1t# vault operator unseal
After the third run you’ll see the Sealed
status changing to false
, meaning
that we’ve successfully unsealed Vault.
Finally, login to Vault using the root token from the previously stored output:
v4u1t# vault login
Token (will be hidden):
Now do the fun part: Generating the root CA!
v4u1t# export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='root-token-here'
v4u1t# vault secrets enable pki
v4u1t# vault secrets tune -max-lease-ttl=87600h pki
v4u1t# vault write -field=certificate pki/root/generate/internal \
common_name="lan" \
issuer_name="root-2022" \
ttl=87600h > root_2022_ca.crt
Let’s check the certificate:
v4u1t# vault read pki/issuer/$(vault list pki/issuers/ | tail -n 1)
Next, we create a role for the root CA and configure the CA and CRL URLs:
v4u1t# vault write pki/roles/2022-servers allow_any_name=true
v4u1t# vault write pki/config/urls \
issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
crl_distribution_points="$VAULT_ADDR/v1/pki/crl"
Now, we generate the intermediate CA:
v4u1t# vault secrets enable -path=pki_int pki
v4u1t# vault secrets tune -max-lease-ttl=43800h pki_int
v4u1t# vault write -format=json pki_int/intermediate/generate/internal \
common_name="LAN Intermediate Authority" \
issuer_name="lan-intermediate" \
| jq -r '.data.csr' > pki_intermediate.csr
v4u1t# vault write -format=json pki/root/sign-intermediate \
issuer_ref="root-2022" \
csr=@pki_intermediate.csr \
format=pem_bundle ttl="43800h" \
| jq -r '.data.certificate' > intermediate.cert.pem
v4u1t# vault write pki_int/intermediate/set-signed \
certificate=@intermediate.cert.pem
Last but not least, we create the certificates:
v4u1t# vault write pki_int/roles/lan \
issuer_ref="$(vault read -field=default pki_int/config/issuers)" \
allowed_domains="lan" \
allow_subdomains=true \
max_ttl="720h" \
key_bits=2048
v4u1t# VAULT_FORMAT=json vault write \
pki_int/issue/lan \
common_name="v4u1t.lan" \
ttl="720h" > /tmp/req
v4u1t# jq --raw-output \
'.data.certificate, .data.issuing_ca' \
/tmp/req > /etc/ssl/vaultwarden.crt
v4u1t# jq --raw-output \
'.data.private_key' \
/tmp/req > /etc/ssl/private/vaultwarden.key
v4u1t# jq --raw-output \
'.data.ca_chain[0], .data.ca_chain[1], .data.certificate, .data.issuing_ca, \
.data.private_key' /tmp/req > /tmp/full.crt
Make sure to import/trust the root CA on all the devices you’re going to be using the Bitwarden clients from.
Option B: Let’s Encrypt
To get an SSL certificate (from Let’s Encrypt) we’ll use OpenBSD’s
acme-client
and set up its configuration, as well as a cron job that will make
sure our certificate gets automatically prolonged.
First, create the file /etc/acme-client.conf
with the following content:
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/ssl/private/letsencrypt.key"
}
domain my.domain.com {
domain key "/etc/ssl/private/vaultwarden.key"
domain certificate "/etc/ssl/vaultwarden.crt"
domain full chain certificate "/etc/ssl/vaultwarden.pem"
sign with letsencrypt
}
Make sure to replace my.domain.com
with the (sub)domain that you pointed to
your cloud instance. Next, we’ll need to configure httpd to run on port 80
and
provide access to the ACME challenge. Create the file /etc/httpd.conf
with
the following content:
server "my.domain.com" {
listen on * port 80
root "/htdocs/my.domain.com"
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
Additionally create the folder /var/www/htdocs/my.domain.com/
and place an
empty index.html
into it.
Let’s enable httpd:
v4u1t# rcctl enable httpd
v4u1t# rcctl restart httpd
We can now issue our SSL certificate by running the following command:
v4u1t# acme-client -v my.domain.com
Next, run crontab -e
. This will open the current crontab for
editing. Add the following line at the end of the table:
0 0 * * * acme-client -v my.domain.com && rcctl restart relayd
Option C: Let’s Encrypt (for Internal Services)
Another possibility for retrieving a valid SSL certificate for use with an internal service (e.g. on the Raspberry or a non-public cloud instance) is using Duck DNS or Cloudflare. Here you can find more info on this approach.
The Password Manager
Next we’re going to take care of the password manager. I initially stated that we’ll be using Bitwarden, but now that you’ve made it this far I feel I can no longer lie to you. We’re not quite going for Bitwarden. Bitwarden – specifically the server part – is a C# .NET and ASP.NET application that we certainly wouldn’t want to deal with on a lean, self-hosted environment like the one we’re setting up. Luckily, there’s an open source alternative to the Bitwarden server that’s written in Rust and can use a SQLite database (amongst others) to store our encrypted vaults: Vaultwarden.
Since Vaultwarden is available as an OpenBSD package, we can install it right away:
v4u1t# pkg_add vaultwarden vaultwarden-web
quirks-6.82 signed on 2022-12-07T11:23:36Z
Ambiguous: choose package for vaultwarden
a 0: <None>
1: vaultwarden-1.26.0p2
2: vaultwarden-1.26.0p2-mysql
3: vaultwarden-1.26.0p2-postgresql
Your choice: 1
...
As we’re not using a dedicated database and instead go with SQLite, the first option is fine for us. However, if you’re looking to serve a broader audience and need to handle more load, the third option might probably make better sense. You will however have to set up a dedicated PostgeSQL database for that, which will require its own set of security enhancements that I won’t be covering here. Alternatively you could trust the AWS or Google engineers with running the database for you and use RDS/Cloud SQL for that matter.
Anyhow, let’s enable the vaultwarden
service:
v4u1t# rcctl enable vaultwarden
The configuration for Vaultwarden is stored in /var/vaultwarden/.env
. You can
adjust the file to your needs, however, here are a few values that should be
configured specifically this way:
DOMAIN=https://v4u1t.lan
WEBSOCKET_ENABLED=true
WEBSOCKET_ADDRESS=127.0.0.1
WEBSOCKET_PORT=3012
Use the DOMAIN
for which you have generated a certificate.
We can now start Vaultwarden:
v4u1t# rcctl start vaultwarden
relayd
Next we set up relayd
as a reverse proxy for Vaultwarden, which takes care of
handling SSL termination. While Vaultwarden could handle SSL on its own, I
suggest using relayd
for this purpose. We’re going to use the following
configuration under /etc/relayd.conf
:
table <vaultwarden-default-host> { 127.0.0.1 }
table <vaultwarden-websocket-host> { 127.0.0.1 }
http protocol vaultwarden-https {
match request header append "X-Real-IP" value "$REMOTE_ADDR"
match request header append "Host" value "$HOST"
match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
match request path "/*" forward to <vaultwarden-default-host>
match request path "/notifications/hub" forward to \
<vaultwarden-websocket-host>
match request path "/notifications/hub/negotiate" forward to \
<vaultwarden-default-host>
tcp { nodelay, sack, backlog 128 }
tls keypair vaultwarden
tls { no tlsv1.0, ciphers HIGH }
http websockets
}
relay vaultwarden-https-relay {
listen on egress port 443 tls
protocol vaultwarden-https
forward to <vaultwarden-default-host> port 8000
forward to <vaultwarden-websocket-host> port 3012
}
In /etc/rc.conf.local
change relayd_flags
to `` (empty). Then launch relayd:
v4u1t# rcctl enable relayd
v4u1t# rcctl start relayd
Further Hardening
We’ve already performed the first few steps in hardening our OpenBSD machine, by enabling hard disk encryption, combined pubkey + password + TOTP authentication and proper configuration of the OpenSSH server. Next we’re going to take a look at a few other areas.
First, enable accton
to have system accounting information
available in /var/account/acct
:
v4u1t# rcctl enable accounting
Next, add bin paths to OpenBSD’s security(8)
checks:
v4u1t# for pth in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin;\
do mtree -cx -p "$pth" \
-K sha256digest,type > /etc/mtree/$(printf "%s" "$pth" | tr '/' '_').secure;\
done; chown root:wheel /etc/mtree/_*.secure && chmod 600 /etc/mtree/_*.secure
Let’s adjust /etc/login.conf
even further and make the default umask
a
little more strict for the future. The login.conf
should now contain the
following changes:
43c43
< :umask=022:\
---
> :umask=027:\
116a117,120
>
> totp:\
> :auth=-totp-and-pwd:\
> :tc=default:
Feel free to also adjust the permission on existing $HOME
folders.
Next, check netstat -na -f inet | grep LISTEN
and make sure only port 443
(HTTPS), port 80
(HTTP, in case you use Let’s Encrypt certificates), and your
SSH port are bound to your system’s public/external IP. Everything else should
only be listening on 127.0.0.1
.
PF
Now, set up the firewall:
##########
# Macros #
##########
minefield="1024:9999"
ssh_alternate_port=31231
##########
# Tables #
##########
table <bruteforce> persist
table <troublemakers> persist
###########
# Options #
###########
set skip on lo
#########
# Rules #
#########
block return # Block stateless traffic
pass # Establish keep-state
# Block brute-forcers
block quick proto tcp from <bruteforce> \
to (egress) port $ssh_alternate_port
block quick proto tcp from <troublemakers> \
to (egress) port $ssh_alternate_port
# By default, do not permit remote connections to X11
block return in on ! lo0 proto tcp \
to port 6000:6010
# Port build user does not need network
block return out log proto {tcp udp} \
user _pbuild
# Connections that made it through to the SSH port but abusing it
pass proto tcp from any to (egress) \
port {$ssh_alternate_port} \
flags S/SA keep state \
(max-src-conn 5, max-src-conn-rate 5/5, \
overload <bruteforce> flush global \
)
# Port 22 is a dead-giveaway
# because we know we moved our SSH server
# elsewhere. Anyone poking there is up to no good.
pass in on egress proto tcp \
from any \
to (egress) port { \
telnet, \
ssh, \
netbios-ns, \
netbios-ssn, \
microsoft-ds \
} \
synproxy state \
tag trouble
# Tag stuff in the range $minefield as trouble ...
pass in on egress proto tcp from any to (egress) port $minefield \
synproxy state \
tag trouble
# ... unless it's to our alternate port
pass in proto tcp \
from any \
to (egress) \
port $ssh_alternate_port \
tag good
# ... or HTTP/HTTPS
pass in proto tcp \
from any \
to (egress) \
port { 80 443 } \
tag good
# Otherwise add to the troublemakers
pass proto tcp from any to (egress) port $ssh_alternate_port \
tagged trouble \
synproxy state \
(max-src-conn 1, max-src-conn-rate 1/10, \
overload <troublemakers> flush global \
)
Feel free to extend the rules to your liking. For further insights on how to manage the state and tables, see this article on undeadly.
Log Forwarding
The (free) Grafana Cloud offers a logs service based on Loki. We
can make use of that to forward our machine’s logs to Grafana, so that we could
set up notifications based on specific log events. Here’s an example of how to
set up log forwarding using promtail
:
v4u1t# pkg_add loki-promtail
v4u1t# cat /etc/promtail/promtail-config.yaml
server:
http_listen_port: 0
grpc_listen_port: 0
positions:
filename: /var/promtail/positions.yaml
clients:
- url: https://xxx@logs-prod-eu-west-0.grafana.net/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log
v4u1t# rcctl enable promtail
v4u1t# rcctl start promtail
You may as well add additional files (outside of /var/log/*log
) to promtail.
Consider however that logs might contain somewhat sensitive info and decide for
yourself whether you’d want to trust Grafana Cloud with that.
For further insights into how to process the logs, check the Loki and Grafana (Cloud) documentation.
Further Enhancements
In the Vaultwarden wiki you can find more info on how to secure your installation, especially if you opted for a public-facing service. Using an alternate base dir is one option, for example. Also make sure to enable 2FA for all Bitwarden accounts on the system and, if not needed, disable functionalities like the Send feature.
Backups are another important topic that I haven’t covered here. Make sure to have a solid backup strategy in place; the Vaultwarden wiki names a few options here as well.
Appendix
Cloud Password Manager Security Issues
- May 2015: LastPass
- 2016: 1Password, MyPasswords, Keeper, LastPass, …
- May 2017: LastPass OneLogin Keeper
- March 2018: Keeper
- February 2019: 1Password, Dashlane, KeePass, LastPass
- May 2020: 1Password, Dashlane, Keeper, LastPass
- April 2021: Passwordstate
- August 2022: LastPass
- November 2022: LastPass
Enjoyed this? Support me via Monero, Bitcoin, Lightning, or Ethereum! More info.