Use Hardware-bound SSH Keys

If you're working with a modern Mac, you have very little excuse not to use hardware-bound SSH keys. When correctly configured, these keys are designed to keep the private key material inside the hardware, making it very difficult for attackers to steal or forge. Add biometric authentication, and they're much harder for attackers to remotely exploit.

One option is to use a dedicated hardware device, like a YubiKey. But on a supported Mac, you can also use the built-in Secure Enclave.

A separate security key, strictly speaking, has several advantages, such as a tiny attack surface and advanced features. That said, the Secure Enclave is a convenient way to get hardware protection without buying another device, and is miles better than using software keys.

Recent versions of macOS include sc_auth commands for creating identities protected by the Secure Enclave. The examples below use Apple's bundled SSH tools; check man sc_auth and man ssh-keychain on your Mac for support. The biometric examples also require Touch ID.

Generating SSH Keys

First, make sure you have SSH_SK_PROVIDER set in your shell's startup file (for example, ~/.zshrc). This tells OpenSSH to use Apple's keychain provider:

export SSH_SK_PROVIDER=/usr/lib/ssh-keychain.dylib

Run that line in your current shell too, or open a new terminal before continuing. Then create a non-exportable key pair protected by the Secure Enclave, requiring biometric authentication for key use:

# Create a non-exportable P-256 identity with biometric authentication
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio

# Load identities into the macOS SSH agent
/usr/bin/ssh-add -K

Here, -l ssh is just the identity's label. The -ne suffix in p-256-ne is what makes the key non-exportable. With SSH_SK_PROVIDER set, ssh-add -K loads identities through that provider.

To get the associated public key, use ssh-add -L. Copy the matching public key to your target host's authorized_keys, your GitHub account, or whichever service you use:

# List public keys loaded in the agent
/usr/bin/ssh-add -L

# List CryptoTokenKit identities with SSH-style fingerprints
sc_auth list-ctk-identities -t ssh

No Biometrics

You can also create keys that don't require biometric authentication, using -t none instead of -t bio. These are handy for background automation, like periodically syncing your Obsidian Git repository:

# Create a non-exportable P-256 identity without biometric authentication
sc_auth create-ctk-identity -l ssh-automation -k p-256-ne -t none
/usr/bin/ssh-add -K

The private key is still non-exportable, but software running as you can request signatures without a Touch ID prompt. Give an automation key only the access it needs.

Exportable Keys

For the p-256-ne keys above, the private key material is protected by the Secure Enclave and cannot be exported in plaintext. When SSH authenticates, the enclave performs the private-key operation. This also means you can't transfer the private key to another Mac or back it up for use elsewhere.

For typical SSH usage, non-exportable keys are the approach I'd recommend, particularly for highly sensitive access. However, if you need to take the same private key with you, you can create exportable keys instead:

# Create an exportable P-256 identity with biometric authentication
sc_auth create-ctk-identity -l ssh-exportable -k p-256 -t bio
/usr/bin/ssh-add -K

These keys are encrypted using a Secure Enclave-backed key, but the SSH private key itself can be exported. The p-256 key type enables this.

You can then move the identity with a PKCS#12 archive:

# List identities and find the hash for the one labeled ssh-exportable
sc_auth list-ctk-identities

# Export it; replace IDENTITY_HASH with that identity's hash
umask 077
sc_auth export-ctk-identity -h IDENTITY_HASH -f ssh-identity.p12

# On the destination Mac, import the archive with biometric protection
sc_auth import-ctk-identities -f ssh-identity.p12 -t bio
/usr/bin/ssh-add -K

Set SSH_SK_PROVIDER on the destination Mac as well. Treat the .p12 file as private key material: biometric protection on the Mac doesn't protect a copy you've exported. See man sc_auth for the -p archive password option.

Key Attestation

For organizations, administrators might want to enforce the use of hardware-bound keys. A public key alone doesn't prove where its private key was generated or how it's protected.

Key attestation provides signed evidence about a key's origin. With a trusted attestation chain and the relevant device metadata, a verifier can check the manufacturer and model and apply a policy about acceptable hardware. The exact guarantees depend on the attestation scheme; attestation doesn't universally prove that every use requires biometrics.

Apple provides Managed Device Attestation for managed deployments, including hardware-bound identities provisioned through ACME. Note that this is a completely separate enrollment workflow.

YubiKeys support FIDO2 attestation and can be a good fit when an organization needs to verify which hardware created a credential. For SSH, you still need an enrollment process that validates attestation before authorizing the key; simply using a YubiKey doesn't establish that policy. Yubico also has a guide to SSH with FIDO2 keys.

What About Non-Macs?

If you're using Linux and your machine has an available TPM 2.0 chip, you can use tpm2_ptool and the PKCS#11 provider from tpm2-pkcs11 to protect SSH keys with the TPM. This is part of the TPM2 Software project.

The project's SSH setup guide walks through the process.