Skip to content
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

Make relogin attempts use the strongest auth method #11781

Merged
merged 4 commits into from
Apr 8, 2022

Conversation

codingllama
Copy link
Contributor

Fixes a potential stdin hijacking bug by making relogin attempts default to a single MFA method (the strongest available).

The problematic scenario is as follows:

  1. User has both OTP and security keys registered
  2. "Relogin" is triggered via a tsh command (say, tsh logout; tsh ssh --proxy=example.com llama@myserver)
  3. User is prompted to pick either OTP or security key ("Tap any security key or enter a code from a OTP device")
  4. An stdin read is fired in the background to read the OTP code (via prompt.Stdin)
  5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a relogin is triggered by a long living tsh invocation (again, tsh ssh ...): in this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the problem for all relogin invocations. tsh login behavior remains the same.

Note that we have to default to cluster's most secure method without checking the user devices. The user is not logged in yet, thus the backend cannot reveal any information about that user.

Fixes #11709.

@github-actions github-actions bot added the tsh tsh - Teleport's command line tool for logging into nodes running Teleport. label Apr 6, 2022
@codingllama
Copy link
Contributor Author

Tested on master using tsh both with and without libfido2 support - both work fine.

In regards to the stdin hijack, the problem is a bit more nuanced than the description. There are roughly two ways in which we read from stdin: os.Stdin.Read([]byte) and term.ReadPassword. Neither call can be interrupted after it starts. I did some research and tried a bunch of obtuse methods just in case - writing to stdin, closing stdin, opening/closing stdin a separate File, so on. Most don't work, some don't work and make things a lot worse. :)

I think there are two viable technical options out of this: 1. taking full control of the terminal (raw mode) or 2. running tc.Login in a separate process. 1. is tough on portability, likely difficult to implement and may or may not solve anything. 2. makes tsh way more complex than I would like.

The TL;DR is that a UX change that avoids the issue is the best call. @zmb3 took this up with some folks and we seem to be happy with this workaround, so here it is.

codingllama added a commit that referenced this pull request Apr 6, 2022
@codingllama
Copy link
Contributor Author

Confirmed that changes work for v9 (codingllama/v9-hungry-hungry-tsh). Prepping a v8 backport now.

@codingllama
Copy link
Contributor Author

Friendly ping @greedy52 @smallinsky ?

lib/client/api.go Outdated Show resolved Hide resolved
lib/client/mfa.go Outdated Show resolved Hide resolved
@codingllama codingllama force-pushed the codingllama/hungry-tsh-ssh branch 2 times, most recently from f8bba4e to 95d9117 Compare April 7, 2022 18:52
@codingllama
Copy link
Contributor Author

Thanks, @greedy52.

@smallinsky, let me know if you'd like to take a look or if you are happy for me to merge with the current approvals.

@codingllama
Copy link
Contributor Author

I'll go ahead and merge this one so I can get the backports going. Happy to address any comments in a future PR.

@codingllama codingllama merged commit 9abdb2a into master Apr 8, 2022
@codingllama codingllama deleted the codingllama/hungry-tsh-ssh branch April 8, 2022 20:54
codingllama added a commit that referenced this pull request Apr 8, 2022
Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
   `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
   enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
   prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Fixes #11709.

* Add UseStrongestAuth flag to PromptMFAChallenge
* Add TeleportClient.UseStrongestAuth and set it true for relogin
* Proper testing
* Address review comments
codingllama added a commit that referenced this pull request Apr 8, 2022
Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
   `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
   enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
   prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Issue #11709.
codingllama added a commit that referenced this pull request Apr 11, 2022
Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
   `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
   enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
   prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Issue #11709.
codingllama added a commit that referenced this pull request Apr 11, 2022
…1848)

Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
    `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
    enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
    prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Issue #11709.

* Make relogin attempts use the strongest auth method (#11781)
* Fix conflicts for v8
codingllama added a commit that referenced this pull request Apr 11, 2022
Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
   `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
   enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
   prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Fixes #11709.

* Add UseStrongestAuth flag to PromptMFAChallenge
* Add TeleportClient.UseStrongestAuth and set it true for relogin
* Proper testing
* Address review comments
codingllama added a commit that referenced this pull request Apr 11, 2022
…1847)

Fixes a potential stdin hijacking bug by making relogin attempts default to a
single MFA method (the strongest available).

The problematic scenario is as follows:

1. User has both OTP and security keys registered
2. "Relogin" is triggered via a tsh command (say,
   `tsh logout; tsh ssh --proxy=example.com llama@myserver`)
3. User is prompted to pick either OTP or security key ("Tap any security key or
   enter a code from a OTP device")
4. An stdin read is fired in the background to read the OTP code (via
   prompt.Stdin)
5. User picks the security method, thus the stdin read is "abandoned"

In most cases this is fine, as the program ends right after. The issue is when a
relogin is triggered by a long living tsh invocation (again, `tsh ssh ...`): in
this case the stdin hijack causes input to be swallowed.

Forcing a single MFA option avoids the potential stdin hijack, fixing the
problem for all relogin invocations. `tsh login` behavior remains the same.

Note that we have to default to cluster's most secure method _without_ checking
the user devices. The user is not logged in yet, thus the backend cannot reveal
any information about that user.

Issue #11709.

* Make relogin attempts use the strongest auth method (#11781)
* Fix conflicts for v9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-required tsh tsh - Teleport's command line tool for logging into nodes running Teleport.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tsh ssh when authenticating eats the first two keypresses
3 participants