SSH Agent Forwarding

jeffutter
jeffutter
Community Member
edited March 2022 in SSH

I'm really enjoying using 1Password as a ssh-agent with biometric unlock. I'm wondering if it's possible forward the SSH agent though.

Scenario:

I have two macs with 1Password setup with biometric unlock for ssh keys (work machine and personal).
Occasionally, I want to login from my pesonal. machine and git push on my work machine. If I attempt to do this now, I get errors like this:

sign_and_send_pubkey: signing failed for ED25519 "/Users/MyName/.ssh/id_ed25519" from agent: agent refused operation
sign_and_send_pubkey: signing failed for RSA "SSH Key" from agent: agent refused operation
git@github.com: Permission denied (publickey).

I think what's happening is that ssh on my work machine is trying to use the 1password agent with biometric unlock, but the machine is locked (display asleep) so the biometric prompt is immediately dismissed and the auth fails.

I'm wondering if I can forward the SSH agent from my personal machine to the work machine. I would expect ssh -A work to handle this, but it seems to get the same error as above.

Any ideas on how to do this, or do I have to forgo biometric unlock if I want to ssh from the machines remotely.


1Password Version: 8.7.0
Extension Version: Not Provided
OS Version: macOS 12.3

Comments

  • jc00ke
    jc00ke
    Community Member

    I'd be interested in the solution to this w/o biometric unlock for the Linux use case. I have 2 Linux machines, one laptop and one desktop. I'm currently ssh'd into the desktop but I can't then SSH tunnel that machine to another because I can't unlock the desktop. Hopefully that makes sense.

  • Michael Mercurio
    Michael Mercurio
    Community Member

    This is also a problem for me. I have agent forwarding enabled in my ~/.ssh/config. I also have 1Password configured as the IdentityAgent like this:

    Host *
        IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
        ForwardAgent yes
    

    When I ssh into my iMac remotely and then attempt to use ssh from there (e.g., via git) the option for IdentityAgent is used (i.e., the locked 1Password as the agent) and NOT the forwarded agent from my local MacBook. I would like the forwarded agent to be used instead of the locked 1Password on my remote iMac.

    I suspect this is not a problem specific to 1Password, and instead related to how the OpenSSH options for ForwardAgent and IdentityAgent interact.

    Does anyone know of a way to configure the OpenSSH client to prefer the forwarded agent over the configured IdentityAgent?

    As a workaround for this I often disable the IdentityAgent option (comment it out in my ~/.ssh/config) when I'm ssh'd in remotely, but this is a pain and not ideal. You could also disable the option via command line but this is also not ideal, and not really possible when ssh is used via git and similar.

  • Michael Mercurio
    Michael Mercurio
    Community Member
    edited June 2022

    This seems to work for me.

    Instead of configuring 1Password's SSH Agent via ~/.ssh/config, I instead rely on the environment variable SSH_AUTH_SOCK. In my ~/.zshrc I do this:

    # Set SSH_AUTH_SOCK to use 1Password as SSH Agent when not ssh'd in remotely.
    if [ -z $SSH_TTY ] ; then
        SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock
    fi
    

    This gives me the behavior I'm looking for: when I'm working on my Mac locally (SSH_TTY is not set), the local instance of 1Password is used. When I'm ssh'd into my Mac remotely, the forwarded agent is used (I have ForwardAgent yes in my ~/.ssh/config as indicated in my previous post. This allows me to always use the 1Password instance running on my local Mac, even when ssh'd into another host remotely and that host may also be running 1Password.

    I'm curious if there are other ways to accomplish this.

    Cheers,
    Michael

    Update: oops. I had the logic reversed in my original post. fixed.

  • Michael Mercurio
    Michael Mercurio
    Community Member

    Today, I realized a shortcoming of the solution I posted above. It doesn't work when calling ssh from non-interactive terminal sessions such as iTerm Profiles or other apps not launched from the terminal. In these cases, SSH_AUTH_SOCK is not set and 1Password is not used as the SSH Agent.

    The ideal solution would be if OpenSSH had a way to configure multiple SSH Agents to use in priority order, but I'm not aware such a thing exists.

    For the basic case of SSH Agent forwarding as asked by the OP, the solution I proposed works well for me.

  • fliphess
    fliphess
    Community Member
    edited June 2022

    I have the same issue, but because I'm using multiple SSH keys and I use the IdentityFile option as mentioned in the advanced config (https://developer.1password.com/docs/ssh/agent/advanced) to select a specific key to each server, I cannot use the snippet mentioned earlier in this thread because that gives me the error from the openssh agent:

    Load key "<mykey>.pub": invalid format
    

    Both the IdentityFile and the IdentityAgent options support environment variables, so I could create a mapping to set the IdentityFile for each host using env vars, and set it to an empty string if connecting over SSH, but with more than 50 entries in my ssh config and a separate key for each host, this makes my profile settings and ssh_config overly complex.

    Is there anyone that found a better solution to work around this?

  • mjakl
    mjakl
    Community Member

    I specify the forwarded agent explicitly when I need it (which is correctly set in the $SSH_AGENT_SOCK environment variable):

    ssh -o IdentityAgent=$SSH_AUTH_SOCK your.host.name
    

    For git, this would be (solving the OPs question):

    GIT_SSH_COMMAND="ssh -o IdentityAgent=$SSH_AUTH_SOCK" git push
    

    Background: The agent forwarding works fine, but the IdentityAgent setting in .ssh/config takes precedence over the SSH_AUTH_SOCK environment variable set by ssh. It seems to be possible to use environment variables in the .ssh/config file as well (specifically for the IdentityAgent setting), but I believe this won't work for non-terminal applications.

    It's not perfect, but works for me.

    HTH

  • epxap
    epxap
    Community Member

    Hey everyone, thought i'd post my solution in case it helps anyone looking to setup agent forwarding with 1Password.

    The solution was to rely on file paths instead of environment variables as most GUI apps don't have a way of setting environment variables.

    Make both changes on the remote machine:
    1. ~/.ssh/rc contents (don't forget to chmod +x this file):

    # create/update symlink only if interactive ssh login AND ~/.ssh/ssh_auth_sock doesn't exist AND $SSH_AUTH_SOCK does exist
    if [[ -n "$SSH_TTY" && ! -S ~/.ssh/ssh_auth_sock && -S "$SSH_AUTH_SOCK" ]]; then
        ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
    fi
    
    1. ~/.ssh/config contents:
    # override IdentityAgent parameter for all hosts if forwarded SSH agent is present
    Match host * exec "test -S ~/.ssh/ssh_auth_sock"
        IdentityAgent ~/.ssh/ssh_auth_sock
    
    # use 1password ssh agent as default
    Match host *
        IdentityAgent /path/to/1password/agent.sock
    

    Explanation

    The ssh rc script runs everytime an ssh connection is made. It updates the symlink ~/.ssh/ssh_auth_sock with the path specified by $SSH_AUTH_SOCK, which is the path to the forwarded ssh agent.

    The first match in the ssh config only succeeds if the symlink is valid, and if so, uses that as the IdentityAgent. If the first match fails, then IdentityAgent will be set to local instance of 1Password instead. The order is important – SSH will use the first obtained value for a parameter, so when the symlink is valid, it'll set it as the IdentityAgent and ignore the second IdentityAgent line.

    Works when i'm locally at the machine and when connected via SSH – with both CLI and GUI apps!

  • mangnus
    mangnus
    Community Member

    Any suggestion on how to handle situations where $SSH_TTY or $SSH_AUTH_SOCK is not available? When I connect to my iMac from Blink shell for iOS I only have $SSH_CONNECTION available.

  • malo
    malo
    Community Member

    @mangus, have a look at the Advanced: SSH section of the Blink docs. If you want to use agent forwarding, you need to either use ssh -A or set ForwardAgent to YES in your Blink host config (config -> Hosts -> [host] -> SSH Config).

    To get my Mac to use the forwarded agent when I connect to it over SSH with Blink, but still use 1Password when I'm working on my Mac locally I've been using the following in my ~/.ssh/config file:

    Match host * exec "test -z $SSH_TTY"
      IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
    

    This sets 1Password as the IdentityAgent only when $SSH_TTY isn't set, which is the case when I'm working locally on my machine. When I SSH in using Blink with agent forwarding, $SSH_TTY is set along with $SSH_AUTH_SOCK (which is used by any commands, e.g., git, to do SSH authentication).

  • acarlton
    acarlton
    Community Member

    I'm also struggling with this and looking for a clean solution.

  • We're considering to have op-ssh-sign check for SSH_TTY / SSH_CONNECTION and SSH_AUTH_SOCK, and if both are set, use SSH_AUTH_SOCK instead. That should remove the need for these SSH config and rc file snippets.

    We'll keep this thread posted if we have any updates on this.

  • datwaft
    datwaft
    Community Member

    I got this working using @malo solution but it doesn't work when trying to use SSH signing with 1Password.

    My workaround right now is to manually remove gpg.ssh.program from .gitconfig when connecting to the remote over SSH and then adding it again when using the remote computer in person.

  • Hi @datwaft:

    If you're looking to use 1Password SSH agent commit signing on a device when accessed locally as well as remotely, your best bet is to ensure that $SSH_AUTH_SOCK is set to your forwarded agent socket when SSH'd into that device, and then the 1Password SSH agent socket when you're using it in person.

    SSH signing by default uses the agent pointed to by $SSH_AUTH_SOCK. and setting op-ssh-sign as the SSH program overrides that function.

    Jack

  • datwaft
    datwaft
    Community Member

    I saw that in the documentation and tried to do something like that but it didn't work for me.
    I just tried once again and it seems to work, I probably had the wrong socket set to SSH_AUTH_SOCK.

    Quick question, is ~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock always the path to the 1Password agent socket or it can change in the future? I want to see if I should hardcode it in my dotfiles with a condition like test -z $SSH_TTY.

  • Hi @datwaft:

    Great question. While it's possible that the path to the agent may change in the future, there aren't any plans or intent to change it.

    Additionally, that path will be the same on every macOS install, and won't vary based on the specific Mac computer it's installed on.

    Jack

  • jgoz
    jgoz
    Community Member

    Here's a simple redirect script that I use as my gpg.ssh.program setting in gitconfig. It's based on @floris_1P's comment above and can be used as a placeholder until op-ssh-sign supports this natively:

    git-ssh-sign

    #!/bin/bash
    
    if [[ "$SSH_CONNECTION" ]] && [[ "$SSH_AUTH_SOCK" ]]; then
        ssh-keygen "$@"
    else
        /Applications/1Password.app/Contents/MacOS/op-ssh-sign "$@"
    fi
    

    In gitconfig:

    [gpg "ssh"]
      program = /path/to/git-ssh-sign
    
  • Thanks for sharing @jgoz!

    Jack

  • We're considering to have op-ssh-sign check for SSH_TTY / SSH_CONNECTION and SSH_AUTH_SOCK, and if both are set, use SSH_AUTH_SOCK instead. That should remove the need for these SSH config and rc file snippets.

    Just wanted to follow up here that this has now been implemented!

  • tuxtof
    tuxtof
    Community Member

    good news
    starting which version ?

  • Starting with version 8.10.4.

  • btaroli
    btaroli
    Community Member

    Will a description of this also be back-ported to the docs so the unaware might discover it more easily? :)

  • Yes, definitely!

This discussion has been closed.