Contents
It’s been several years since I went through all the trouble of setting up my own GPG keys and securing them in YubiKeys following [drduh’s guide](https:/…
Contents
It’s been several years since I went through all the trouble of setting up my own GPG keys and securing them in YubiKeys following drduh’s guide. With that approach, you generate one key securely offline and store it on multiple YubiKeys, along with a backup.
It has worked well for me for years, and as the Lindy effect suggests, it would almost certainly continue to.
But as my sub-keys were nearing expiration, I was faced with either renewing (more convenient, no forward secrecy) or rotating them (rather painful, but potentially more secure). However, I’ve realized that I essentially only use these keys for encryption, and almost never for signing. So, instead of doing either of the usual options, I’m going to let my keys expire entirely.
I’m now experimenting with age, which touts itself as “simple, modern, and secure encryption”. If needed, I will use minisign for signatures.
Workflow changes
This required changing a couple of things in my typical workflow.
Password manager
First, and foremost, I needed to switch from pass to passage, a fork of pass that uses age as the backend. This was actually surprisingly easy because passage includes a simple bash script to do the migration.
#! /usr/bin/env bash
set -eou pipefail
cd "${PASSWORD_STORE_DIR:-$HOME/.password-store}"
while read -r -d "" passfile; do
name="${passfile#./}"; name="${name%.gpg}"
[[ -f "${PASSAGE_DIR:-$HOME/.passage/store}/$name.age" ]] && continue
pass "$name" | passage insert -m "$name" || { passage rm "$name"; break; }
done < <(find . -path '*/.git' -prune -o -iname '*.gpg' -print0)
There is no installer for passage, and no Arch packages. But it’s easy enough to install because it’s just a shell script you can throw on your $PATH. Note that for Arch, I also needed to install tree, which it assumes you have.
I also name passage as pass on my machine.
The benefit of this is everything that had pass integration has continued to “just work”. For example, aerc, my email client of choice, behaved exactly the same after the migration.
No more gpg-agent
I would occasionally use gpg-agent as my SSH agent on my machines. It was convenient. However, I also like the idea of having a dedicated SSH key per machine. It makes monitoring their usage and revoking them much finer-grained.
The absence of gpg-agent forced me to set up new keys on all my machines and add them to various servers/services.
Benefits of the age approach
Easy encryption with chezmoi
While I was tending to the encryption area of my personal tech “garden”, I also started leveraging chezmoi’s encryption features. I already use chezmoi for my configuration files, but with encryption, I could also easily add “secrets” to my public dotfiles repo. In my case so far, this just means my copies of my favorite paid font: Berkeley Mono.
chezmoi also has a nice guide for configuring chezmoi to encrypt while asking for a passphrase only once for age.
Easy YubiKey configuration
I was also very pleasantly surprised with how easy it was to switch to age! Last time I set up the GPG keys on my YubiKeys, I spent several hours.
This time, with the help of age-plugin-yubikey and embracing the idea of having unique keys on each YubiKey, but encrypting everything for multiple recipients, setting up my keys was surprisingly trivial. It also generates the keys securely on the hardware key itself, which is nice. The whole process probably took 30 minutes. It was so easy that in the future, I’m very much not intimidated by the thought of rotating keys.
Thoughts
Did I need to switch to age? Of course not.
However, over my career, I repeatedly find that exploring new tools for your core workflows (part of investing in interfaces) is just plain fun. I often learn new ways of thinking about problems. Sometimes, you walk away with a new default that brings some fresh ideas and some delight to your life. Other times, you walk away with your trusty old tool, with greater appreciation for its history and the hard-earned approach it has established. For my uses at the moment, age definitely falls into the former camp.
Posts from blogs I follow
On Async Mutexes
A short note on contradiction or confusion in my language design beliefs I noticed today.
via matklad November 04, 2025
`SocketAddrV6` is not roundtrip serializable
An investigation into some lesser-known IPv6 features.A few weeks ago at Oxide, we encountered a bug where a particular, somewhat large, data structure was erroring on serialization to JSON via serde. The problem was that JSON only supports map keys that a…
via sunshowers November 04, 2025
Generated by openring-rs from my blogroll.