RSS Amplifier

Signs of Triviality · Mar 18, 2026

SSH Key Handling using the macOS keychain and 1Password

0
Sign in to vote or save

netmeister.org

March 17th, 2026

Use of SSH keys is ubiquitous, and while I like SSH certificates even better, SSH keys are still great. But you do have to keep the private key, well, private. We normally do that by encrypting the private key with a passphrase, but of course that incurs all the usual issues inherent in passphrase management: picking a strong passphrase, having to remember or store that passphrase, having to enter the passphrase, and so on.

To avoid having to enter a lengthy passphrase every time we use the private key, we can make use of an SSH agent, meaning we have to provide the passphrase only once. But we're lazy and really would prefer the number of times we enter the passphrase to be zero, since otherwise we'll inevitably set it to be "password123".

So here are two convenient ways to never (or only exactly once) have to enter your SSH key's passphrase by example of macOS:

1. Store the passphrase in the macOS keychain

macOS provides a custom ssh_config option to automatically use the keychain for SSH. This is a seamless integration and allows you to use SSH completely without any agents and still not have to manually type your passphrase.

In order to take advantage of this, just add the UseKeychain yes option to your ~/.ssh/config. After that, the first time you use a key, you will be prompted for the passphrase and the system will then store it in the keychain and supply it in the future non-interactively:

$ grep UseKeychain ~/.ssh/config
UseKeychain yes
$ ssh -i ~/.ssh/mykey some-host hostname
Enter passphrase for key '/Users/jschauma/.ssh/mykey':
hostname.example.com
$ ssh-add -l
The agent has no identities.
$ ssh -i ~/.ssh/mykey -v -v some-host true 2>&1 | grep keychain
debug2: using passphrase from keychain
$ 

Note that even though we are not using an agent, we are not prompted for a passphrase the second time around, but ssh(1) fetched it from the keychain automatically as shown in the debug output.

Now I'd have liked to show you the item in the keychain using the security(1) command, but the passphrase is placed in the "Local Items" keychain, which appears to be inaccessible to the security(1) tool. Direct sqlite3 access to ~/Library/Keychains/*/keychain-2.db doesn't help, either, since everything's encrypted, of course. In addition, the item was added using an Key Chain Access Group Entitlement of com.apple.ssh.passphrases; /usr/bin/ssh can access it because it has that entitlement. I'll illustrate these properties below:

$ security find-generic-password -s "SSH: /Users/jschauma/.ssh/mykey"
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.
$ echo "SELECT rowid,acct,agrp,data,
    datetime(mdat + 978307200, 'unixepoch', 'localtime') AS last_modified
    FROM genp
    WHERE agrp = 'com.apple.ssh.passphrases'
    ORDER BY mdat DESC
    LIMIT 1;" | sqlite3 ~/Library/Keychains/*/keychain-2.db
31926|luINe褞V-?&?:?:?^]$?|com.apple.ssh.passphrases|^H|2026-03-17 11:39:18
$ codesign -d --entitlements - /usr/bin/ssh
Executable=/usr/bin/ssh
[Dict]
[...]
	[Key] keychain-access-groups
	[Value]
		[Array]
			[String] com.apple.ssh.passphrases
$ 

Just sharing these commands above because it took me a while to find them as I was looking for ways to get the key from the command-line and understand the different restrictions. (Arguing with AI about the many different ways it hallucinated for how to retrieve the key using the command-line was a big waste of time, of course.) Anyway, where were we?

...but still use an agent

Of course not having added this key to your agent means that you can't forward it to another system. If you do need that, then add AddKeysToAgent yes to your ~/.ssh/config. This option works just fine in combination with UseKeychain, but comes with the caveat that many SSH servers have a default of how many authentication attempts they permit: OpenSSH, for example, defaults to MaxAuthTries 6. That is, if you have more than six keys in your agent, you might be unable to log in because the server closes the connection before your agent can even offer the right key.

The workaround for that is to specify an explicit IdentityFile and enable IdentitiesOnly in your config file for the given host. For example:

$ cat ~/.ssh/config
UseKeychain yes
AddKeysToAgent yes
Host *ip.linodeusercontent.com
        IdentityFile ~/.ssh/linode
        IdentitiesOnly yes
Host *amazonaws.com *.ip.aws
        IdentityFile ~/.ssh/aws
        IdentitiesOnly yes
$ ssh 50-116-63-125.ip.linodeusercontent.com true
Enter passphrase for key '/Users/jschauma/.ssh/linode':
$ ssh-add -l
256 SHA256:tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0 (ED25519)
$ ssh -v 50-116-63-125.ip.linodeusercontent.com true 2>&1 | grep agent
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: agent returned 1 keys
debug1: Will attempt key: /Users/jschauma/.ssh/linode ED25519 SHA256:tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0 explicit agent
debug1: Offering public key: /Users/jschauma/.ssh/linode ED25519 SHA256:tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0 explicit agent
debug1: Server accepts key: /Users/jschauma/.ssh/linode ED25519 SHA256:tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0 explicit agent
$ 

Cool! We can use our agent, but don't have to type our passphrase even after a reboot, because the keychain will supply it. Pretty cool. But there's another way to do this:

2. Use 1Password

If you use 1password, you can also store your SSH keys directly in your password manager. This is particularly neat, because it now allows you to use biometric authentication to unlock the key, and thus doesn't involve a passphrase at all. The secret key remains in the 1Password vault.

The documentation provided by 1Password is excellent, so you can just follow it. The one thing to pay attention to is the above mentioned limitation on the number of keys in your agent. When using 1Password for your keys, your private SSH key doesn't live in your ~/.ssh/ directory, so in order to use the IdentityFile directive, you need to use the "SSH Bookmarks" feature in 1Password. That creates a separate ~/.ssh/1Password/config file, which you can include from your normal configuration file.

Alternatively, you can of course also just populate your normal config file with the pathnames for the public keys found in the ~/.ssh/1Password/ directory. The file names are based on the public key fingerprint, so maybe creating memorable symlinks might be useful:

$ ls ~/.ssh/1Password
config
SHA256_2LPQtjSsvmKvMRTZovolV95osJ6gV9KN9aoRrRKaDtw.pub
SHA256_fB9lcd3sLYCBdupp+spKBHqlcAvKvxyHzt3MLf+rrl8.pub
SHA256_NUI+Qd8mJ8HsZrIiGChLaEf0b8Ge6JyLDw0NvAZgt_I.pub
SHA256_tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0.pub
$ file -h ~/.ssh/agent.sock
/Users/jschauma/.ssh/agent.sock: symbolic link to /Users/jschauma/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock
$ ssh-add -l
The agent has no identities.
$ SSH_AUTH_SOCK=~/.ssh/agent.sock ssh-add -l
256 SHA256:tSQphFDPCfX58d9LvdxErSv6CBf2B8fFYTB+d2AqmA0 Linode SSH Key (ED25519)
256 SHA256:NUI+Qd8mJ8HsZrIiGChLaEf0b8Ge6JyLDw0NvAZgt/I Some SSH Key (ED25519)
256 SHA256:2LPQtjSsvmKvMRTZovolV95osJ6gV9KN9aoRrRKaDtw Another SSH Key (ED25519)
256 SHA256:fB9lcd3sLYCBdupp+spKBHqlcAvKvxyHzt3MLf+rrl8 EC2 SSH Key (ED25519)
$ ln -s ~/.ssh/1Password/SHA256_tSQp* ~/.ssh/1Password/linode.pub
$ ln -s ~/.ssh/1Password/SHA256_fb9* ~/.ssh/1Password/aws.pub
$ cat ~/.ssh/config
Host *ip.linodeusercontent.com
        IdentityAgent "~/.ssh/agent.sock"
        IdentityFile ~/.ssh/linode.pub
        IdentitiesOnly yes
Host *amazonaws.com *.ip.aws
        IdentityAgent "~/.ssh/agent.sock"
        IdentityFile ~/.ssh/aws.pub
        IdentitiesOnly yes
$ 

Our default SSH agent does not have any keys, but the 1Password ٰSSH agent does. With that in place, you should now be able to see a prompt for authentication using 1Password requesting to use the SSH private key stored in your vault:

Terminal screenshot showing an
                 ssh command with a 1Password
                 fingerprint dialog over it.

Note that it says that there are 4 keys in the agent, but due to the IdentityFile directive, it will use that key explicitly, as intended instead of iterating over all keys.

The SSH keys you store in 1Password will of course be available on all systems where you have access to 1Password. This is both useful (for obvious reasons) and possibly risky: you may in fact want to have different SSH keys for access to a server from different devices, and if you have access to multiple vaults (e.g., a work environment vault as well as a personal vault), you absolutely need to make sure you are placing the right keys into the right vault.

Now there are of course many other ways to handle your SSH keys, and other password managers may also offer SSH agent support. The solutions I wrote down here just worked for me, and hopefully are useful to somebody else out there. ✌

March 17th, 2026


Links:

Read the original on netmeister.org

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.