Apple's Secure Enclave SSH Keys Work, But the Touch ID Prompt Is Ugly

Protecting SSH Keys with macOS Secure Enclave

Apple's Secure Enclave SSH Keys Work, But the Touch ID Prompt Is Ugly

After worrying that SSH keys in ~/.ssh could be copied by any malicious script, I tried macOS's native Secure Enclave support. The private key never leaves the chip, and Touch ID approval is required for every signing operation. Setup uses sc_auth and ssh-keygen, but the Touch ID dialog says 'ctccardtoken needs to authenticate' instead of something friendly. It works, yet the unpolished UI pushed me toward Secretive.

My sense of beauty is not compatible with this ugliness, so I will be looking into other solutions to store my SSH keys in Secure Enclave such as Secretive.
  1. anaisbetts

    Never missing an opportunity for self-promotion, if you use a lot of machines and have issues with agent forwarding and Git (i.e. because you're using a remote coding agent), I wrote https://github.com/anaisbetts/ts-ssh-agent - your keys are stored on a remote Tailscale node, and agent signing requests are verified via your Tailscale identity and gated by Tailscale access rules.

    This means the machines you want have access to SSH (i.e. GitHub push/pull), but none of them have an actual SSH key - if a machine is compromised you drop it from Tailscale. More of a security/usability compromise than what OP is looking for, but solved a lot of frustrating paper cuts for me - I use it every day and I never think about SSH agents any more, it all just works

  2. database64128

    Security features like this works, until it doesn't.

    When I installed WireGuard on macOS, I was happy to discover that it stores private keys in the system keychain. Accessing the private key requires Touch ID.

    Then one day after a system upgrade, the WireGuard app crashed on startup with:

    [APP] Unable to open config from keychain: -25300

    Then the app deleted all profiles because they are all "orphaned", apparently for "keychain consistency" [0].

    From then on, I just use a text editor to edit my WireGuard configuration files, and import them to the app. The bug still exists to this day [1].

    [0] https://github.com/WireGuard/wireguard-apple/commit/dfb685f2...

    [1] https://www.reddit.com/r/WireGuard/comments/wyt828/osx_wireg...

  3. jwr

    I decided years ago that I want to protect my keys with a hardware device that is independent of the vendor of the machine that I'm currently using. I also want to have backup keys and I want to be able to freely move them around various physical locations. Or have a backup shipped to me across the world if necessary.

    YubiKeys were the only solution that fit these requirements, so I went with those. I have been using them for the last ten years or so and I've been very happy with this solution. See https://github.com/drduh/YubiKey-Guide for a description of how to make your RSA keys stored on YubiKeys work with GPG and SSH at the same time.

  4. mavam

    One fundamental problem with agentic development is that accessing the secure enclave key requires human presence. If you're running headless and aren't logged in, Secretive (not sure about others) will not be able to access the enclave, even when you only chose "notify" and not "touchid".

    This is why I'm skeptical that the approach can scale reliably, even though I'm relying on it today. (Yes, PATs would fix this, but the enclave model is what I'm trying to retain for now.) What I've done instead is wrote a small daemon that sets the SSH authentication socket and does agent forwarding. This works when I'm traveling with laptop...but not yet from my mobile phone.

    Example:

    Laptop Remote Mac

    ┌─────────────────────┐ ┌──────────────────────────┐

    │ Secretive │ │ ssh / git commit -S │

    │ (Secure Enclave) │ │ │ │

    │ ▲ │ ForwardAgent │ ▼ │

    │ └── ssh ─────┼─────────────────►│ ~/.ssh/agent.sock │

    │ │ │ (stable proxy) │

    └─────────────────────┘ │ │ │ │

    │ ▼ ▼ │

    │ forwarded local │

    │ laptop Secretive │ […]

  5. LeBit

    The article starts on an incorrect premise.

    The author says he doesn’t like the idea of having keys sitting on his file system ready to be snatched by bad actors.

    That’s why they should be passphrase protected.

    You use ssh agent to store the keys in memory and for convenience you can store the passphrases in keychain. MacOS OpenSSH has the UseKeychain config directive for that.

    I use Yubikey/FIDO2 myself, but not because private keys cannot be protected on a file system.

  6. flexorium

    I’ve been a happy user of Secretive for years, including for Git commit signature which it make it a separate key with interaction but not for pull / push. I find the trade off ideal for GitHub.com and have other keys with different setup for servers.

    SSH keys in plaintext was one of the first thing that bagel [0] our developer endpoint secret detection focused on. Then we embedded bagel as a library in our developer endpoint protection [1].

    [0] https://boostsecurityio.github.io/bagel/

    [1] https://boostsecurityio.github.io/dazio/docs/install/

  7. jen729w

    I use 1Password's `op` for this, but with an allowance: my dev environment keys.

    I found I was getting fingerprint fatigue. Do I need a fingerprint request every time my dev server wants to connect to dev Supabase? No. That's expected, and zero risk. There's no data there.

    I worried that a nefarious request would be auto-approved by me. When you see 20 requests a day, your muscle memory just reaches for the sensor.

    So I have a separate 1Password vault that a service account [0] can read. That token is in my environment as OP_SERVICE_ACCOUNT_TOKEN, which the `op` tool understands.

    It also has access to a vault with 'AI-safe' keys that I want Claude to be able to access without asking me.

    Now, these requests work invisibly. And when I see a fingerprint popup, it's unusual, and I don't auto-approve by habit.

    I also keep an item called '_One-day keys' in a separate vault. (The underscore just pushing it to the top of the list for easy access.)

    It has prod keys, mostly restricted read-only. If required, I move that over to the open vault. Claude knows this item and has instructions to remind me to move it back out when it's finished what it was doing.

    [0]: https://www.1password.dev/service-accounts/get-started

  8. dylanger

    You should checkout the TKey (https://www.tillitis.se/products/tkey/)

    It's effectively an open source version of a YubiKey, the hardware itself is all open source and it handles ed255519 SSH keys really well.

    inb4 they're not the same, I know, I really like what the TKey team is doing.

More from this day

2026-11-11