1Password and SSH_ASKPASS

Security, Compliance, Resilience, Automation


1Password has an excellent solution for managing SSH keys securely using their 1Password SSH Agent. However I interact with a few devices that either require keyboard-interactive multi-factor authentication (MFA) or force the use of a password instead of accepting keys or certificates.

Thankfully, through the use of the 1Password CLI, the SSH_ASKPASS environment variable, and a little shell script, we can use 1Password to fill in these MFA tokens and passwords too.

The script, op_ssh_askpass further below, is expected to be used as follows:

# MFA example:
$ op_ssh_askpass 'op://Private/secsvr/one time password?attribute=otp' -- secsvr

# Password example:
$ op_ssh_askpass 'op://Private/legacy server/password' -- root@legacysvr

The way the script works is to detect if it is being invoked directly or by the SSH client.

If invoked directly, it sets up the necessary environment variables to tell SSH to invoke the same script whenever SSH is prompting for a password (or MFA token) and then invokes the SSH client with the provided arguments.

If invoked by SSH, the script simply reads the secret from 1Password, triggering a biometric input from me if needed, and outputs the secret to stdout, as SSH expects in this context, automating the credential input.

Here is the complete op_ssh_askpass script:

#!/bin/bash

main () {
    if [ -n "$OP_SSH_ASKPASS_SECRETREF" ]; then
        op read "${OP_SSH_ASKPASS_SECRETREF}"
        return $?
    fi

    if [ -z "$1" ]; then
        printf 'Usage: %s op://<vault>/<item>/<field> -- <ssh args...>\n' "$0"
        return 1
    fi

    local _script_dir=$(cd "$(dirname "$0")" && pwd)
    SSH_ASKPASS="${_script_dir}/$(basename "$0")"
    SSH_ASKPASS_REQUIRE=force
    OP_SSH_ASKPASS_SECRETREF="$1"
    shift
    export OP_SSH_ASKPASS_SECRETREF SSH_ASKPASS SSH_ASKPASS_REQUIRE

    if [ "$1" = "--" ]; then
        shift
    fi

    ssh "$@"
    return $?
}

main "$@"

My primary desktop OS is Windows 11 with WSL2, there may be other solutions more appropriate to other environments.

Naturally, these commands can be aliased or wrapped in a function for convenience, and I have done in my own environment.

The script could also be extended to support additional features, such as handling a server that has both a password prompt and an MFA prompt, or fetching additional SSH args from other fields in a 1Password item.