hashicorp / vault

A tool for secrets management, encryption as a service, and privileged access management
https://www.vaultproject.io/
Other
31.33k stars 4.23k forks source link

CLI MFA prompt incorrectly printed to stdout #23283

Open willhaines opened 1 year ago

willhaines commented 1 year ago

Describe the bug Running vault login -no-store -token-only ... incorrectly prints the Enter the passphrase for methodID prompt to stdout, rather than stderr. This breaks the workflow of storing the token directly to an env variable, and not persisting it to disk.

To Reproduce Steps to reproduce the behavior:

$ export VAULT_TOKEN=$(vault login -no-store -token-only -method=ldap username=<user>)
Password (will be hidden): 
Initiating Interactive MFA Validation...
$ echo $VAULT_TOKEN
Enter the passphrase for methodID "4d073558-5c90-11ee-8c99-0242ac120002" of type "duo": 
hvs.<token>

Expected behavior

MFA prompt is printed to stderr, and only token goes to stdout.

$ export VAULT_TOKEN=$(vault login -no-store -token-only -method=ldap username=<user>)
Password (will be hidden): 
Initiating Interactive MFA Validation...'
Enter the passphrase for methodID "4d073558-5c90-11ee-8c99-0242ac120002" of type "duo": 
$ echo $VAULT_TOKEN
hvs.<token>

Environment:

divyaac commented 1 year ago

Hi @willhaines - Correct me if I'm wrong - the issue you're facing is that you would like to store the token of an in interactive login method through a single command. The reason that we have this configured in the current way is the logically, the result of the line vault login -no-store -token-only -method=ldap username=<user> is another interactive login step (not just the vault token).

However, if you feel that there is a better way to do this with the current code patterns, we would be happy to review your PR or assist you with that as well!

willhaines commented 11 months ago

Hi @divyaac ,

Thanks for the feedback, I've submitted a PR to address this behavior. Just to clarify a bit, the existing behavior is inconsistent. There's three total "prompts" when authenticating in this way, two of which go to stderr and one to stdout. My proposed change would send all three to stderr.

Current behavior: Password (will be hidden): -> stderr Initiating Interactive MFA Validation... -> stderr Enter the passphrase for methodID "4d073558-5c90-11ee-8c99-0242ac120002" of type "duo": -> stdout hvs.<token> -> stdout

Proposed behavior (implemented in #24629): Password (will be hidden): -> stderr Initiating Interactive MFA Validation... -> stderr Enter the passphrase for methodID "4d073558-5c90-11ee-8c99-0242ac120002" of type "duo": -> stderr hvs.<token> -> stdout

This behavior would be more consistent, and make it possible to do an interactive login while capturing the token to an environment variable. We like this workflow because it keeps the token from being stored to disk or displayed on the screen.

biazmoreira commented 9 months ago

Hi @willhaines, could you give us more information as to why "This breaks the workflow of storing the token directly to an env variable, and not persisting it to disk" this is happening?

Thank you!

willhaines commented 9 months ago

Hi @biazmoreira, I'd be happy to clarify that.

Without MFA

Before enabling MFA in Vault, we would often use the following workflow to authenticate and capture the result to an env variable:

$ export VAULT_TOKEN=$(vault login -no-store -token-only -method=ldap username=<user>)
Password (will be hidden): 

It worked really well because the password prompt was printed to stderr and only the token was printed to stdout. This way the user sees the expected interactive steps in their terminal, and the VAULT_TOKEN env variable is correctly populated with the new token, like so:

$ echo $VAULT_TOKEN
hvs.<token>

With MFA

With MFA now enabled on our Vault server, the vault login command generates additional prompts (which makes total sense). Unfortunately, one of those prompts is printed to stdout, which breaks the convenient separation we were taking advantage of. Now when the user tries to capture the VAULT_TOKEN in the same way, they do not see the second MFA prompt in their terminal, which can be confusing.

$ export VAULT_TOKEN=$(vault login -no-store -token-only -method=ldap username=<user>)
Password (will be hidden): 
Initiating Interactive MFA Validation...

What's worse, though, is that the VAULT_TOKEN env variable now contains some prompt text in addition to the actual token and thus is not valid for executing Vault requests.

$ echo $VAULT_TOKEN
Enter the passphrase for methodID "4d073558-5c90-11ee-8c99-0242ac120002" of type "duo": 
hvs.<token>

Background

We started using this workflow because some of our workstations did not have encrypted disks, and we did not want to persist tokens in plaintext. Even with an encrypted disk, we've found it to be quite useful when working with multiple Vault servers (eg dev, test, prod) because you can authenticate with each server in a separate terminal. It is also useful when testing permissions if you need to compare the behavior of test-user1 and test-user2, for instance.

Even if this is a niche use-case that is not widely shared, I still think that the login process should be consistent. All three prompts should be printed to the same place, whether that is stdout or stderr. The authentication workflow shouldn't be split across the two streams.