Every time I log into a server or push code to GitHub, a small USB key on my laptop flashes. I have to touch it to continue.
That extra tap blocks a class of attacks that’s far more common now than twenty years ago: malware stealing or abusing your SSH keys.
Setting this up takes little more effort than distributing new SSH keys every couple of years.
In this post I’ll cover why you should take that extra time and explain how to use the technology you can adopt to achieve this.
Covered below are:
Twenty years ago, my rough education about malware attacks suggested they:
Today, especially after cryptocurrency and ransomware made attacks more profitable, well-funded attackers focus on professionals and infrastructure. [1]
Twenty years ago, these attack vectors would have seemed theoretical. Only the most valuable targets would have faced them:
The balance has shifted, but operating systems have not caught up with usable isolation for professional work. The exception is ambitious projects like Qubes. [9] We need other measures. Touch-verified SSH is an inexpensive, low-impact intervention that helps.
If you have used SSH with public and private keys to push to GitHub or log into servers, you will recognize this experience:
After rebooting your machine, you try to push to a Git repository. You are prompted for a key password, or perhaps you configured the system to unlock your key at login. Either way, subsequent Git operations require no password.
This relies on the ssh-agent protocol, integrated with your operating system: Keychain on macOS, GNOME Keyring on Linux, or the standard OpenSSH implementation on Windows.
This interaction dates to 1995, when SSH was introduced as "freeware," before OpenSSH existed.
The model has two critical weaknesses:
Touch-verified SSH solves both problems:
Apple laptops after 2018 excel at having hardware to make touch verification work smoothly, at no additional hardware cost. Touch ID uses a "Secure Enclave" co-processor, an isolated secondary computer with restricted communication. That's the fingerprint reader in the upper-right corner by the keyboard.
Unfortunately, macOS does not include SSH agent support for Touch ID/Secure Enclave. You will need Secretive.
In my experience, and that of the Ubicloud team, Secretive is extremely reliable. Beyond fingerprint verification, it can store non-touch-verified keys in the secure enclave for development work. These keys require no touch but cannot be copied, providing a security bonus for less-critical tasks.
Secretive guides you through creating enclave-resident keys. Just distribute the public key to servers needing authentication, like any SSH public key.
Each key use triggers a notification about the cryptographic operation, making unexpected activity from compromised machines more visible.
The software is impressive. The author deserves recognition.
Since I do not use macOS daily, I rely on FIDO2 security keys: USB devices costing $10-$60.
You can use FIDO2 security keys on macOS too, though Apple's OpenSSH builds lack FIDO2 support. Installing via brew install openssh provides FIDO2-enabled OpenSSH. Why Apple did not include this functionality is unclear—it could be an oversight.
Many vendors make FIDO2 security keys. Yubico's YubiKeys are well-known and offer "nano"-scale USB-C products essential for laptops without USB-A ports. I prefer nano products to reduce damage risk; they are too small to snag on anything.
Ubicloud provides two keys per staff member: one primary, one backup. Some prefer larger backup keys with nano primaries.
These keys also work for WebAuthn ("passkey") authentication on websites. As with SSH, hardware touch verification is far more secure than software-only variants in password managers or browsers.
After buying and plugging in a security key, run:
ssh-keygen -t ed25519-sk
This prints something like:
Generating public/private ed25519-sk key pair.
Follow the usual SSH keypair steps, including setting an encryption passphrase.
Distribute the public key to servers or GitHub as normal.The key works like any SSH key, except you must touch the hardware for authentication during git push or ssh. You might wonder how security improves when it generates a "private key" file with passphrase encryption. The answer: calling it a private key is practical mis-naming. [11] It is actually a key handle. This handle combines with a private key held in the hardware. Together, they derive the real private key that matches the public key seen in id_ed25519_sk.pub.
Thus, you need both the "private key" file and matching hardware to authenticate.
An optional but highly recommended step is to disable OTP mode on YubiKeys. You'll notice this if accidentally touching the key makes it type random strings like:
ccccccjlkgjlevtdernkbbnrrvhcvdbljgchbgbdbvgk
This creates chaos when typed into Gmail, GitHub, or applications with hotkeys. Unless you specifically need OTP, disable it. Install ykman via Homebrew, apt, or other means, then run:
ykman config mode FIDO
Remove and reinsert the YubiKey. It remembers this setting permanently.
Also retrieve your YubiKey's serial number. Though printed on the device (even nano ones), it's hard to read:
ykman list --serials
You can uninstall ykman afterward.
Since these keys cannot be cloned or copied, you will likely maintain multiple keys for redundancy, convenience, or multiple computers.
Everyone occasionally replaces hardware. With macOS and Secretive, this happens every few years since keys cannot transfer between devices.
This raises questions about which keys to invalidate and how to link each key with its required hardware.
Given the low number of keys per person and infrequent changes, a simple approach works well: maintain a Git repository with an authorized_keys format file:
[email protected]
AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAILChQ1wpGdpxlrs448d98x6/F1xKmXOSfJ5pzJ4DExLOA
AAABHNzaDo= daniel+24345989@ubicloud.com [email protected]
AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKLkgjxaqNssfWx35m1sALAvTFg+Wi1rBOOixXv56u7RA
AAABHNzaDo= daniel+26335085@ubicloud.com ecdsa-sha2-nistp256
AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFkGB1JeNyhEhK+6u7PsGVFcsNuTawnm/G8YbxpZpW3bm8aodOAkNbEJjyzRZmlN9Yp/bwW0HX8eXLFWUHH9460= [email protected]
Group each person's keys together. The file works directly as ~/.ssh/authorized_keys.
You need a complete list of every active key. This lets you match key digests from OpenSSH's LogLevel VERBOSE output with specific people and hardware. [12] The output looks like this:
Aug 29 04:11:36 vmb0zabr sshd[1265]: Accepted publickey for ubi from 2601:645:c57e:6a80:3aa6:4732:81fd:ba3c port 42526 ssh2: ED25519-SK SHA256:gfLueg2RoqE7w6g7wcQeNcyOE8TbqhkOgXJetXe7HCQ
A Git repository gives you timestamped commits and pull requests that show who added which keys and when. Branch protection and reviews add approval records, making auditing and compliance work the same way as code.
The comment section (last column) identifies the person and hardware. I use email addresses for precise identification, combined with Gmail's "plus addressing" to include hardware serial numbers. I prefer serial numbers: they are often written on the surface of the device by the manufacturer. This makes identification possible even for broken or powered-down hardware.
Both YubiKeys and Apple computers have serial numbers written onto the surface of the device. They are also available via software. For YubiKeys, use ykman list --serials. For Apple computers, use ioreg -l | grep IOPlatformSerialNumber.
I reserve touch verification for production systems and maintain some touch-unverified keys too.
This reduces mistakes: touching the security key reminds me to increase caution. Using it for all work weakens this effect. I encourage staff to submit touch-unverified keys in separate authorized_keys files alongside production keys. These serve as development substitutes and ease staff collaboration.
I consider GitHub pushes important enough for touch verification. Malicious code pushes without my consent could be catastrophic. I also have commit access to widely-used non-Ubicloud repositories. Given touch verification's ease, I have an ethical obligation to reduce compromise risk through my laptop.
Watch for unexpected touch requests: they may indicate machine compromise. Be alert if you must touch the key twice for one intended action repeatedly, as one of those touches might assist malicious software.
The world today is far more subtle and malicious in targeting software engineers. There are only a few low-cost measures that can make a real difference. This is one of them.