smallstep / cli

🧰 A zero trust swiss army knife for working with X509, OAuth, JWT, OATH OTP, etc.
https://smallstep.com/cli
Apache License 2.0
3.67k stars 256 forks source link

[Bug]: step ssh certificate only adds the cert to ssh-agent and not the private key #1016

Closed redrac closed 1 year ago

redrac commented 1 year ago

Steps to Reproduce

Run step ssh certificate user@company.com /home/user/.ssh/id_ecdsa and attempt to SSH to a host with the user CA installed; the SSH client will prompt you for a passphrase for the private key.

Your Environment

Expected Behavior

I would expect both the certificate and the key to be added to the agent. Both are required for SSHing to a host.

user@host01 [16:05:37] ~ $ ./wrapper_step -a
Visit https://company.okta.com/activate and enter the code: (press 'ENTER' to open default browser)
ZZZZZZZZ
step ssh certificate --force --not-after "12h" --token "MY_TOKEN" "user@company.com" "/home/user/.ssh/id_ecdsa"
✔ CA: https://step-ca.company.com
Please enter the password to encrypt the private key:
✔ Private Key: /home/user/.ssh/id_ecdsa
✔ Public Key: /home/user/.ssh/id_ecdsa.pub
✔ Certificate: /home/user/.ssh/id_ecdsa-cert.pub
✔ SSH Agent: yes

user@host01 [16:05:47] ~ $ ssh-add -l
256 SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/OAvwmabJI/4 /home/user/.ssh/id_ecdsa (ECDSA-CERT)
256 SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/OAvwmabJI/4 /home/user/.ssh/id_ecdsa (ECDSA)

user@host01 [16:33:26] ~ $ ssh host02
Last login: Wed Sep 20 23:24:59 2023 from 10.x.x.x
user@host02:~$

Actual Behavior

What actually happens is only the certificate is added and then you cannot SSH to a host with the CA configured in the SSH server configuration:

user@host01 [16:40:01] ~ $ ./wrapper_step -a
Visit https://company.okta.com/activate and enter the code: (press 'ENTER' to open default browser)
ZZZZZZZZ
step ssh certificate --force --not-after "12h" --token "MY_TOKEN" "user@company.com" "/home/user/.ssh/id_ecdsa"
✔ CA: https://step-ca.company.com
Please enter the password to encrypt the private key:
✔ Private Key: /home/user/.ssh/id_ecdsa
✔ Public Key: /home/user/.ssh/id_ecdsa.pub
✔ Certificate: /home/user/.ssh/id_ecdsa-cert.pub
✔ SSH Agent: yes

user@host01 [16:40:32] ~ $ ssh-add -l
256 SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/OAvwmabJI/4 /home/user/.ssh/id_ecdsa (ECDSA-CERT)

user@host01 [16:41:10] ~ $ ssh -v host02
OpenSSH_8.9p1 Ubuntu-3ubuntu0.3, OpenSSL 3.0.2 15 Mar 2022
...
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: agent returned 1 keys
debug1: Will attempt key: /home/user/.ssh/id_ecdsa ECDSA-CERT SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/6WH2c+Gt8 agent
debug1: Will attempt key: /home/user/.ssh/id_rsa
debug1: Will attempt key: /home/user/.ssh/id_ecdsa ECDSA SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/6WH2c+Gt8
debug1: Will attempt key: /home/user/.ssh/id_ecdsa_sk
debug1: Will attempt key: /home/user/.ssh/id_ed25519
debug1: Will attempt key: /home/user/.ssh/id_ed25519_sk
debug1: Will attempt key: /home/user/.ssh/id_xmss
debug1: Will attempt key: /home/user/.ssh/id_dsa
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,sk-ssh-ed25519@openssh.com,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com,webauthn-sk-ecdsa-sha2-nistp256@openssh.com>
debug1: kex_input_ext_info: publickey-hostbound@openssh.com=<0>
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering public key: /home/user/.ssh/id_ecdsa ECDSA-CERT SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/6WH2c+Gt8 agent
debug1: Server accepts key: /home/user/.ssh/id_ecdsa ECDSA-CERT SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/6WH2c+Gt8 agent
Enter passphrase for key '/home/user/.ssh/id_ecdsa':
...
Last login: Thu Sep 21 16:33:32 2023 from 10.x.x.x
user@host02:~$

Additional Context

While I couldn't find it explicitly in the man pages I did find note that the private key is required to be in the agent here: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Certificate-based_Authentication.

On the client side, both the user certificate and the private key it corresponds to are needed to log in.

And you can test and confirm that is indeed the case.

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

maraino commented 1 year ago

Hi @redrac, this is quite weird and I cannot reproduce it.

When you see only the ECDSA-CERT in the agent, the agent has both the private key and the certificate. When you see ECDSA too means that it also has the public key, the same one that is available in the certificate. This is the expected behavior:

user@host01 [16:40:32] ~ $ ssh-add -l
256 SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/OAvwmabJI/4 /home/user/.ssh/id_ecdsa (ECDSA-CERT)

I've tried with these version of ssh, but wasn't able to reproduce it:

maraino commented 1 year ago

In my tests, instead of Enter passphrase for key '/home/user/.ssh/id_ecdsa': I see this:

$ ssh -v ssh.host
OpenSSH_8.2p1 Ubuntu-4ubuntu0.9, OpenSSL 1.1.1f  31 Mar 2020
...
debug1: Offering public key: mariano@smallstep.com ECDSA-CERT SHA256:zzz agent
debug1: Server accepts key: mariano@smallstep.com ECDSA-CERT SHA256:zzz agent
debug1: sign_and_send_pubkey: no separate private key for certificate "mariano@smallstep.com"
debug1: Authentication succeeded (publickey).
Authenticated to ssh.host ([x.x.x.x]:22).
...
maraino commented 1 year ago

By the way, I've just noticed that the fingerprints in the ssh-add -l and ssh -v host02 are different:

Can this be related, or are just copypastes from different sessions?

maraino commented 1 year ago

@redrac I've been able to reproduce your behavior, but only if I store the files in /home/user/.ssh/id_ecdsa, it works as expected in any other case.

By the way, you can also use step ssh login user@email.com it will generate an ephemeral key that will be only in the agent.

maraino commented 1 year ago

After looking at the ssh source code, if using a certificate and it is in the default location, it will first use the file instead of the agent. As the SSH server accepts that certificate, the client will ask you for the password of the file.

redrac commented 1 year ago

It was indeed copy paste from different sessions + obscuring my company. Thanks for tracking that down; I confirmed rm -f'ing the files does indeed allow SSH to work with just the cert in agent.