-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Connect: Use SSHAgentLogin when second_factor is set to optional or on #12322
Conversation
I looked at the frontend code of Connect and the only time we send over the |
// bails out to stdin to ask them for it. | ||
// | ||
// Connect cannot do that, but it still wants to use the auth code from lib/client that it | ||
// shares with tsh. So to temporarily work around this problem, we check if the OTP token was |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a plan to properly fix it (vs "temporarily")?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSHAgentMFALogin is CLI-centric, so it is behaving as intended. Teleterm can "borrow" it for the U2F/WebAuthn parts because it happens to use HID instead of stdin, but it's a dangerous game, as SSHAgentMFALogin wasn't created with Web interfaces in mind (and stdin reading plays a part in passwordless webauthn).
The best "fix", IMO, is to let go of tsh-specific methods and go straight to the Proxy API. That means reading the OTP from the Teleterm interface (which, iiuc, we do now) and relying on the CredentialsContainer API for WebAuthn.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tips! At the moment we do have a lot of code copied from tsh. But knowing what to do with the auth methods will help us in deciding which parts of the code we should put inside lib
and share and which parts should actually stay separate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codingllama I looked very briefly at doing webauthn through Chromium in Electron and it might be tricky at the moment because in general webauthn in browsers requires websites to use HTTPS (see electron/electron#24573).
Also, my first reaction to the suggestion of not using tsh-specific methods was "Ahh, but tsh already does a lot of work with the keys it gets in response from that end point, it'd be a shame if we were not able to use that code 😢". What I didn't fully realize at the time is that actually going through the MFA challenge and then processing the response are two distinct steps and we actually just copy-pasted the response-processing code from tsh.
So down the road it should be possible to directly talk to the proxy API and use native browser APIs for webauthn. It's all down to what Electron will allow us to do, but I didn't check that and don't plan to for now.
I'm looking at this atm because we're talking about adding per-session MFA support to Connect which requires the user interacting with a hardware key. And I remembered that the current solution is a bit hacky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
webauthn in browsers requires websites to use HTTPS
Yes, it definitely does. I wouldn't expect that to change.
about adding per-session MFA support to Connect (...)
Caveats aside, I think you should be safe to borrow "PromptMFAChallenge" (or even webauthncli.Login) for MFA challenges. Have a look at the latter, we may even be able to pull some clever stuff with a custom prompt implementation for Connect. Short-term I would suggest looking at dismembering client.SSHAgentMFALogin
so you have better control over user prompts, maybe even preemptively asking for OTPs for example. Give me a nudge if you think I can help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable to me, with the caveats explained in the comments.
// bails out to stdin to ask them for it. | ||
// | ||
// Connect cannot do that, but it still wants to use the auth code from lib/client that it | ||
// shares with tsh. So to temporarily work around this problem, we check if the OTP token was |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSHAgentMFALogin is CLI-centric, so it is behaving as intended. Teleterm can "borrow" it for the U2F/WebAuthn parts because it happens to use HID instead of stdin, but it's a dangerous game, as SSHAgentMFALogin wasn't created with Web interfaces in mind (and stdin reading plays a part in passwordless webauthn).
The best "fix", IMO, is to let go of tsh-specific methods and go straight to the Proxy API. That means reading the OTP from the Teleterm interface (which, iiuc, we do now) and relying on the CredentialsContainer API for WebAuthn.
Fixes gravitational/webapps#793.
tsh always uses
client.SSHAgentMFALogin
for anysecond_factor
option other thanoff
andotp
.teleport/lib/client/api.go
Lines 2686 to 2696 in 8e0421e
If it's set to
on
oroptional
and it turns out the user wants to use an OTP, it bails out to stdin to ask them for it.Connect currently uses the same logic in its switch branches. However, Connect cannot bail out to stdin, but it still wants to use the auth code from
lib/client
that it shares with tsh.So, to temporarily work around this problem, this PR makes it so that we check first if the OTP token was submitted. If yes, then we use
client.SSHAgentLogin
, which lets us provide the token (which we got from the Electron app) and skip asking for it over stdin. If not, we useclient.SSHAgentMFALogin
which should handle auth methods that don't use OTP.I'm not 100% sure if it doesn't break other auth methods, but I think it should work.I'm positive now that it shouldn't introduce regressions for other auth methods. #12322 (comment)If you have webauthn enabled and second_factor set to on/optional, tsh uses a different prompt message:
teleport/lib/client/mfa.go
Lines 137 to 141 in 8e0421e
tsh does that because at this point it doesn't know whether you want to use the hardware key or provide an OTP.
Connect however asks you to select your preferred MFA method before the login attempt:
With the hardware key selected, no OTP code is sent to the tsh daemon that Connect is running, so we know that you wanted to use a hardware key and ask you for it through
client.SSHAgentMFALogin
.This PR would make it so that if the OTP code is sent and
second_factor
is set to on/optional, we route you toclient.SSHAgentLogin
with the code already provided – same path as ifsecond_factor
was set tootp
.