Why

I use 1Password on all my machines to synchronize appropriate credentials between them. I have many VMs and utilities like the ssh-agent make managing ssh credentials easier and safer than leaving unencrypted private keys laying around the filesystem. I've used 1Password since it came out, and now use it at work. 1Password has first-class Linux support and has for a while. However, recently I've tried to use Linux as little as possible for boring and predictable reasons. Since I was a teenager, FreeBSD and OpenBSD have felt like more complete systems and share a kind of (tortured) kinship with MacOS, which I use most of the time.

The 1Password Firefox extension has most of 1Password's functionality and works perfectly on every OS I've tested it on. But it doesn't work offline.

FreeBSD has Linux binary compatibility, so how hard could it be? I wanted to understand how this system works, so I did much of this manually. But! If you want to get Linux apps up and running quickly and are okay with Ubuntu, this guide and its accompanying scripts will be more useful than these exploratory notes. I took many of the scripts and resource files from that guide.

Regardless of what you do, don't use the FreeBSD Handbook recommendation of installing the package for CentOS 7 as the base Linuxulator system. That is woefully outdated for modern systems requiring contemporary dependencies.

Warning

This is more or less a reconstruction of what I did from notes, the current config files on the system I am writing this on, and shell history files. It is bound to be inaccurate and imprecise. Beware, and do not dive into this without comfort in the shell. When I first tried this I somehow messed up my user's uid and had to reset it and the permissions on all my files, both in the chroot and in my user's $HOME directory. Beware.

The Goal

I wanted 1Password running in KDE Plasma with a functional clipboard, communication with the 1Password Firefox extension, saved 2FA keys for persistent sessions between wallet unlocks, and interaction with hardware Yubikeys.

What I got was just the first part: 1Password 8 running in KDE Plasma with access to the clipboard. The rest of it I haven't figured out, but then again I think I'm moving more towards OpenBSD for my non-Apple machines (and some of the Apple ones) so my next step is experimenting with the 1Password CLI on OpenBSD.

Limitations

  • No hardware Yubikey support for the desktop application. I have Yubikeys working in FreeBSD but the Linux layer doesn't seem to read them. This is probably a permissions or package thing, but I haven't investigated much.
  • No persistent login as 1Password doesn't seem to talk to Kwallet, meaning
  • You have to re-authenticate with 2FA every time you start 1Password
  • No interaction with the Firefox extension; they do not know about each other, so unlocking one does not unlock the other.
  • There is probably some way this increases the envelope of exposure if a threat actor has local access to your machine. I imagine something, somewhere is exposed in a vulnerable way, because I don't have confidence it's not. I'm paranoid though. But don't log into your work account this way until someone from 1Password says it seems okay.

My Setup

I did this on my home gaming PC, an Intel 12700KF with 16 GB of RAM running FreeBSD 13.1-RELEASE on an Intel NVMe.

Guide

The plan

We are going to enable Linux binary compatibility, then set up a basic Debian stable system with the debootstrap package, and point the Linux binary compatibility layer at that directory to use its libraries to run Linux programs.

Enable Linux binary compatibility

Add this to /etc/rc.conf:

linux_enable="YES"

Disable the default mount points by adding the following to /etc/rc.conf

linux_mounts_enable="NO"

Add our eventual Debian home to the Linux emulation path by adding the following to /etc/sysctl.conf:

compat.linux.emul_path="/compat/debian"

Then start the service. This won't do anything yet. It might error out because the location doesn't exist.

# service linux start

Install the base Linux system in a chroot

First install the debootstrap package.

# pkg install debootstrap

Then install Debian stable to /compat/debian. We don't use /compat/linux because that's reserved for the basic and outdated (CentOS-based) compatibility layer provided by emulators/linux_base-c7, which we are avoiding. You don't have to use Debian stable, but I prefer stable OSs on desktops, especially for things like this, where you want to mostly forget about it after getting it working.

To install Debian stable, run the following:

# debootstrap stable /compat/debian https://deb.debian.org/debian

Link the bootstrapped Linux system to the compatibility layer:

# sysctl compat.linux.emul_path="/compat/debian"

chroot into Debian and update the system:

# chroot /compat/debian /bin/bash
root@hostname:/# apt update

From your FreeBSD user account, add a user account for yourself on the Linux installation, making sure the user id and group id match. This assumes you have doas or sudo installed.

# doas chroot /compat/debian groupadd -g $(id -g) $(id -gn)
# doas chroot /compat/debian useradd -u $(id -u) -g $(id -g) $(id -un)

I believe I ran the following to make sure the dependencies for 1Password were loosely present. I don't think most of these are required, as 1Password comes with its own linked ffmpeg, but this might help someone get unstuck.

# apt install pulseaudio ffmpeg curl gpg xterm x11-apps

Configure Linux

I recommend having two terminals open, one for FreeBSD and one chroot-ed into Linux. If you forget which one is which, run stat -c %i /. If it's a low number you're in FreeBSD. A high number means you're in a chroot-ed environment.

In Linux, add the following line to /etc/hosts. My hostname is medusa, and I set it to that in Linux's /etc/hostname for consistency.

127.0.0.1       medusa

Configure permissions

This is where my records get somewhat confused.

To FreeBSD's /etc/fstab, add the following if they aren't already there. debootstrap might have added some of these already. The last line ensures that the Linux and FreeBSD share the temporary filesystem, which seems to keep 1Password and Xorg happy. This Stack Exchange question illustrates solutions to different issues that can come up with respect to Xorg's permissions needs.

devfs      /compat/debian/dev      devfs      rw,late                    0  0
tmpfs      /compat/debian/dev/shm  tmpfs      rw,late,size=1g,mode=1777  0  0
fdescfs    /compat/debian/dev/fd   fdescfs    rw,late,linrdlnk           0  0
linprocfs  /compat/debian/proc     linprocfs  rw,late                    0  0
linsysfs   /compat/debian/sys      linsysfs   rw,late                    0  0
/tmp       /compat/debian/tmp      nullfs     rw,late                    0  0

After adding this, run mount -a to mount everything in /etc/fstab, then check that they're mounted with df -h or your favorite mount listing command.

Restart the Linux emulation service. You might have to replace restart with start.

# service linux restart

At this point, check whether Xorg and Debian can talk by running the following from FreeBSD:

# chroot /compat/debian xeyes

You'll probably get something like Error: Can't open display: :0. We'll create a script to work around that to launch 1Password, but you can try the following if you want to test things directly. If you launch X automatically as root, try running xhost +local:$(id -un) or xhost +local:root. In combination with your user account on the Linux system that matches your FreeBSD user id and group id, should allow you to run Linux X applications.

Install 1Password

Within the chroot-ed Debian environment, follow the instructions for Debian. If it complains about something, you might have, like me, forgotten to install curl or gpg. I don't remember having to do anything special here.

In FreeBSD, create the following script at /usr/local/bin/1password. This is how you'll launch 1Password from the command line. It ensures the right arguments for Electron. You might find this useful if you use other Electron-based applications.

#!/compat/debian/bin/bash

export OPW_PATH="/opt/1Password/1password"
export OPW_WRAPPER="$(readlink -f "$0")"
export LIBGL_DRI3_DISABLE=1
exec -a "$0" "$OPW_PATH" --no-sandbox --no-zygote --test-type --v=0 "$@"

To register 1Password and its onepassword:// URIs with your well-behaved and inclusive desktop environment, create the following file at ~/.local/share/applications/1Password.desktop. The X-KDE-Protocls\=onepassword is KDE-specific. This will help when authenticating your 1Password.com account, as it uses that URI style to communicate with the desktop app.

[Desktop Entry]
Type=Application
Version=1.0
Encoding=UTF-8
Name=1Password
Comment=All your passwords
Icon=1Password
Exec=/usr/local/bin/1password %U
Categories=Application;
MimeType=x-scheme-handler/onepasswd;x-scheme-handler/onepassword;
X-KDE-Protocols=onepassword
StartupNotify=true

If you get stuck

I found a lot of things were fixed or reset by restarting your system. The one thing that didn't stick for me was getting compat.linux.emul_path="/compat/debian" to stick in /etc/sysctl.conf. I don't know what did it, but one day it stuck.

Wrapping up

If you got this far, please let me know how it went!