SSH requires no configuration, but you may put common command line options in ~/.ssh/agent.conf
to avoid repeating them in every invocation.
See (trezor|keepkey|ledger|jade|onlykey)-agent -h
for details on supported options and the configuration file format.
If you'd like a Trezor-style PIN entry program, follow these instructions.
Use the (trezor|keepkey|ledger|jade|onlykey)-agent
program to work with SSH. It has three main modes of operation:
To get your public key so you can add it to authorized_hosts
or allow
ssh access to a service that supports it, run:
(trezor|keepkey|ledger|jade|onlykey)-agent identity@myhost
The identity (ex: identity@myhost
) is used to derive the public key and is added as a comment to the exported key string.
Run
$ (trezor|keepkey|ledger|jade|onlykey)-agent identity@myhost -- COMMAND --WITH --ARGUMENTS
to start the agent in the background and execute the command with environment variables set up to use the SSH agent. The specified identity is used for all SSH connections. The agent will exit after the command completes.
Note the --
separator, which is used to separate trezor-agent
's arguments from the SSH command arguments.
Example:
(trezor|keepkey|ledger|jade|onlykey)-agent -e ed25519 [email protected] -- rsync up/ [email protected]:/home/bob
As a shortcut you can run
$ (trezor|keepkey|ledger|jade|onlykey)-agent identity@myhost -s
to start a shell with the proper environment.
If you just want to connect to a server this is the simplest way to do it:
$ (trezor|keepkey|ledger|jade|onlykey)-agent user@remotehost -c
The identity user@remotehost
is used as both the destination user and host as well as for key derivation, so you must generate a separate key for each host you connect to.
This feature allows using regular SSH-related commands within a subprocess running user's shell.
SSH_AUTH_SOCK
environment variable is defined for the subprocess (pointing to the SSH agent, running as a parent process).
This way the user can use SSH-related commands (e.g. ssh
, ssh-add
, sshfs
, git
, hg
), while authenticating via the hardware device.
Run:
/tmp $ trezor-agent [email protected] -v > hostname.pub
2015-09-02 15:03:18,929 INFO getting "ssh://[email protected]" public key from Trezor...
2015-09-02 15:03:23,342 INFO disconnected from Trezor
/tmp $ cat hostname.pub
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGSevcDwmT+QaZPUEWUUjTeZRBICChxMKuJ7dRpBSF8+qt+8S1GBK5Zj8Xicc8SHG/SE/EXKUL2UU3kcUzE7ADQ= ssh://[email protected]
Append hostname.pub
contents to /home/user/.ssh/authorized_keys
configuration file at ssh.hostname.com
, so the remote server
would allow you to login using the corresponding private key signature.
Export your public key and register it in your repository web interface (e.g. GitHub):
$ trezor-agent -v -e ed25519 [email protected] > ~/.ssh/github.pub
Add the following configuration to your ~/.ssh/config
file:
Host github.com
IdentityFile ~/.ssh/github.pub
Use the following Bash alias for convenient Git operations:
$ alias ssh-shell='trezor-agent ~/.ssh/github.pub -v --shell'
Now, you can use regular Git commands under the "SSH-enabled" sub-shell:
$ ssh-shell
$ git push origin master
The same works for Mercurial (e.g. on BitBucket):
$ ssh-shell
$ hg push
For more details, see the following great blog post: https://calebhearth.com/sign-git-with-ssh
$ trezor-agent -e ed25519 user@host --shell
$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeAmtnhHlyg4dzGP3/OF4WHX7NoYhClS98EK22q/O5+ <ssh://user@host|ed25519>
$ git config --local user.signingkey "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeAmtnhHlyg4dzGP3/OF4WHX7NoYhClS98EK22q/O5+"
$ git config --local gpg.format ssh
$ git config --local commit.gpgsign true
$ git config --local gpg.ssh.allowedSignersFile $PWD/.git/allowed-signers
$ echo "user@host ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeAmtnhHlyg4dzGP3/OF4WHX7NoYhClS98EK22q/O5+" >> $PWD/.git/allowed-signers
$ git commit --allow-empty --message="Testing SSH signing"
[master 4a1f730] Testing SSH signing
$ git log --show-signature -1
commit 4a1f730d7f70fd31a0bda334734d0ac4dc9d97ad (HEAD -> master)
Good "git" signature for user@host with ED25519 key SHA256:aESFjLsydJHQg1vnAkq42jQDkCcn4Tde4J+v+0XFmwM
Author: Roman Zeyde <[email protected]>
Date: Fri Oct 21 18:34:09 2022 +0300
Testing SSH signing
$ cat .git/config
[user]
signingkey = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeAmtnhHlyg4dzGP3/OF4WHX7NoYhClS98EK22q/O5+
[gpg]
format = ssh
[commit]
gpgsign = true
[gpg "ssh"]
allowedSignersFile = /home/user/Code/test-git-ssh-sig/.git/allowed-signers
Replace trezor
with keepkey
or ledger
or jade
or onlykey
as required.
[Unit]
Description=trezor-agent SSH agent
Requires=trezor-ssh-agent.socket
[Service]
Type=simple
Restart=always
Environment="DISPLAY=:0"
Environment="PATH=/bin:/usr/bin:/usr/local/bin:%h/.local/bin"
ExecStart=/usr/bin/trezor-agent --foreground --sock-path %t/trezor-agent/S.ssh IDENTITY
If you've installed trezor-agent
locally you may have to change the path in ExecStart=
.
Replace IDENTITY
with the identity you used when exporting the public key.
IDENTITY
can be a path (starting with /
) to a file containing a list of public keys
generated by Trezor. I.e. /home/myUser/.ssh/trezor.conf
with one public key per line.
This is a more convenient way to have a systemd setup that has to handle multiple
keys/hosts.
When updating the file, make sure to restart trezor-agent.
If you have multiple Trezors connected, you can select which one to use via a TREZOR_PATH
environment variable. Use trezorctl list
to find the correct path. Then add it
to the agent with the following line:
Environment="TREZOR_PATH=<your path here>"
Note that USB paths depend on the USB port which you use.
[Unit]
Description=trezor-agent SSH agent socket
[Socket]
ListenStream=%t/trezor-agent/S.ssh
FileDescriptorName=ssh
Service=trezor-ssh-agent.service
SocketMode=0600
DirectoryMode=0700
[Install]
WantedBy=sockets.target
systemctl --user start trezor-ssh-agent.service trezor-ssh-agent.socket
systemctl --user enable trezor-ssh-agent.socket
export SSH_AUTH_SOCK=$(systemctl show --user --property=Listen trezor-ssh-agent.socket | grep -o "/run.*" | cut -d " " -f 1)
Make sure the SSH_AUTH_SOCK variable matches the location of the socket that trezor-agent
is listening on: ps -x | grep trezor-agent
. In this setup trezor-agent should start
automatically when the socket is opened.
SSH and ssh-keygen can make and verify signatures, see https://www.agwa.name/blog/post/ssh_signatures.
See here for more ssh protocol details:
- https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig
- https://github.com/openssh/openssh-portable/blob/master/sshsig.c
- https://github.com/openssh/openssh-portable/commit/2a9c9f7272c1e8665155118fe6536bebdafb6166
$ trezor-agent -e ed25519 [email protected] | tee ~/.ssh/trezor-github.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIvcbhXyaXXNytCLTDfEMlLuwEhtfo0XmPP1U5RsnOZ4 <ssh://[email protected]|ed25519>
$ trezor-agent -e ed25519 [email protected] -- ssh-keygen -Y sign -f ~/.ssh/trezor-github.pub -n file README.md
Signing file README.md
Write signature to README.md.sig
$ cat allowed
[email protected] ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIvcbhXyaXXNytCLTDfEMlLuwEhtfo0XmPP1U5RsnOZ4 <ssh://[email protected]|ed25519>
$ ssh-keygen -Y verify -f allowed -I [email protected] -n file -s README.md.sig -vvv < README.md
debug1: sshsig_verify_fd: signature made with hash "sha512"
debug1: sshsig_wrap_verify: verify message length 64
debug1: Valid (unverified) signature from key SHA256:6UBhPb5SOoCUfasGC1/aCBegYov0/P3ajd6eNbYg77A
debug1: parse_principals_key_and_options: allowed:1: matched principal "[email protected]"
debug1: allowed:1: matched key and principal
Good "file" signature for [email protected] with ED25519 key SHA256:6UBhPb5SOoCUfasGC1/aCBegYov0/P3ajd6eNbYg77A
If SSH connection fails to work, please open an issue
with a verbose log attached (by running trezor-agent -vv
) .
Note that your local SSH configuration may ignore trezor-agent
, if it has IdentitiesOnly
option set to yes
.
IdentitiesOnly
Specifies that ssh(1) should only use the authentication identity files configured in
the ssh_config files, even if ssh-agent(1) or a PKCS11Provider offers more identities.
The argument to this keyword must be “yes” or “no”.
This option is intended for situations where ssh-agent offers many different identities.
The default is “no”.
If you are failing to connect, save your public key using:
$ trezor-agent -vv [email protected] > ~/.ssh/hostname.pub
And add the following lines to ~/.ssh/config
(providing the public key explicitly to SSH):
Host hostname.com
User foobar
IdentityFile ~/.ssh/hostname.pub
Then, the following commands should successfully command to the remote host:
$ trezor-agent -v [email protected] -s
$ ssh [email protected]
or,
$ trezor-agent -v [email protected] -c