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

interactive CLI for mfa login #14131

Merged
merged 20 commits into from
Feb 24, 2022
Merged

interactive CLI for mfa login #14131

merged 20 commits into from
Feb 24, 2022

Conversation

hghaf099
Copy link
Contributor

@hghaf099 hghaf099 commented Feb 17, 2022

This PR is a step to improve CLI for mfa login. For a login request that is subject to MFA validation, it interactively asks user for credentials to validate the request, and return the client token.
Also, enabled audit backend in a test to make sure mfa/validate is audited.

Example of the CLI output in interactive mode:

vault write auth/userpass/login/alice -format=json @/tmp/alice_pwd.json

Enter the passphrase for methodID "3b7bac01-9792-d870-5c24-ff70af7ccb0d": 
{
  "request_id": "56ce9b00-d008-faec-4ff2-e46a4f5b8dc5",
  "lease_id": "",
  "lease_duration": 0,
  "renewable": false,
  "data": null,
  "warnings": null,
  "auth": {
    "client_token": "s.d0zwd86n4yuFxMIkr14EQJTB",
    "accessor": "DpMaT5UksUhUOuytgDSkVtrE",
    "policies": [
      "default"
    ],
    "token_policies": [
      "default"
    ],
    "identity_policies": null,
    "metadata": {
      "username": "alice"
    },
    "orphan": true,
    "entity_id": "f69c3147-5994-b078-9cea-94918b7f4ccd",
    "lease_duration": 2764800,
    "renewable": true,
    "mfa_requirement": null
  }
}

raskchanky and others added 11 commits February 11, 2022 12:52
* Delete an MFA methodID only if it is not used by an MFA enforcement config

* Fixing a bug: mfa/validate is an unauthenticated path, and goes through the handleLoginRequest path
* preventing replay attack on MFA passcodes

* using %w instead of %s for error
CLI prints a warning message indicating the login request needs to get validated
@vercel vercel bot temporarily deployed to Preview – vault February 17, 2022 19:30 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 17, 2022 19:30 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 17, 2022 19:39 Inactive
@vercel vercel bot temporarily deployed to Preview – vault February 17, 2022 19:39 Inactive
Base automatically changed from vault-4554-oss to main February 17, 2022 21:08
@vercel vercel bot temporarily deployed to Preview – vault February 18, 2022 01:46 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 18, 2022 01:46 Inactive
@hghaf099 hghaf099 marked this pull request as ready for review February 18, 2022 18:19
@hghaf099 hghaf099 marked this pull request as draft February 18, 2022 19:13
command/write.go Outdated
"mfa_payload": mfaPayload,
}
path = "sys/mfa/validate"
goto WRITE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather see the write code repeated than have this goto.

command/write.go Outdated
@@ -150,11 +155,97 @@ func (c *WriteCommand) Run(args []string) int {
c.UI.Warn(wrapAtLength("A login request was issued that is subject to "+
"MFA validation. Please make sure to validate the login by sending another "+
"request to mfa/validate endpoint.") + "\n")
ok := YesNoPrompt("Would you like to interactively validate MFA methods?", true)
if ok {
mfaPayload := make(map[string][]string, 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you extract this into a func so we can use return instead of goto?

@vercel vercel bot temporarily deployed to Preview – vault February 19, 2022 03:10 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 19, 2022 03:10 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 19, 2022 03:14 Inactive
@vercel vercel bot temporarily deployed to Preview – vault February 19, 2022 03:14 Inactive
@hghaf099 hghaf099 requested a review from ncabatoff February 22, 2022 15:13
@hghaf099 hghaf099 marked this pull request as ready for review February 22, 2022 16:56
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 22, 2022 17:01 Inactive
@vercel vercel bot temporarily deployed to Preview – vault February 22, 2022 17:01 Inactive
command/base.go Outdated
Name: "non-interactive",
Target: &c.flagNonInteractive,
Default: false,
Usage: "It controls a command to be executed in an interactive or non-interactive fashion with a user.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Usage: "It controls a command to be executed in an interactive or non-interactive fashion with a user.",
Usage: "When set true, prevents asking the user for input via the terminal.",

Default: false,
Usage: "It controls a command to be executed in an interactive or non-interactive fashion with a user.",
})

}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also use github.com/mattn/go-isatty to override the var to true when we can't ask the user for input (because there's no tty)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is less desirable, because then if the user didn't say -non-interactive, but they're running without a terminal, we'll simply block waiting for input on stdin. This will be a surprising change and it won't be obvious what the problem is.

command/write.go Outdated
var passcode string
var err error
if usePasscode {
passcode, err = c.UI.AskSecret(fmt.Sprintf("Enter the passphrase for methodID %q:", mfaMethodID))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could tell them the method type, not sure if we have that info.

command/write.go Outdated
if usePasscode {
passcode, err = c.UI.AskSecret(fmt.Sprintf("Enter the passphrase for methodID %q:", mfaMethodID))
if err != nil {
c.UI.Error(fmt.Sprintf("failed to read the passphrase with error %q. please validate the login by sending a request to mfa/validate", err.Error()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
c.UI.Error(fmt.Sprintf("failed to read the passphrase with error %q. please validate the login by sending a request to mfa/validate", err.Error()))
c.UI.Error(fmt.Sprintf("failed to read the passphrase with error %q. please validate the login by sending a request to sys/mfa/validate", err.Error()))

command/write.go Outdated
}
} else {
// TODO: not sure about printing this message; an error might occur before or during the validate request
c.UI.Warn("Please acknowledge the push notification in your authenticator app")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we prompt them (e.g. "hit enter") so we know when they've done it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, at this point, the validate request has not issued yet. This is just a reminder for them to check their authenticator app. There is a chance that the validate request fails even before issuing the notification.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Maybe we can make the message a little more explicit then, something like "Asking Vault to perform MFA validation with upstream service. You should receive a push notification in your authenticator app shortly"? Otherwise if they go and look immediately they might not see the push yet.

@vercel vercel bot temporarily deployed to Preview – vault February 22, 2022 18:45 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 22, 2022 18:45 Inactive
@hghaf099 hghaf099 requested a review from ncabatoff February 22, 2022 21:45
@hghaf099 hghaf099 added this to the 1.10-rc1 milestone Feb 23, 2022
Copy link
Contributor

@raskchanky raskchanky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, modulo Nick's outstanding comment(s).

…nd non-interactive. A user without a terminal should not be able to use the interactive mode.
@vercel vercel bot temporarily deployed to Preview – vault February 24, 2022 19:53 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook February 24, 2022 19:53 Inactive
@hghaf099
Copy link
Contributor Author

I tested the following combinations:

  • method using passcode in interactive mode
  • method using passcode in non-interactive mode
  • method not using passcode (DUO) in interactive mode
  • method not using passcode (DUO) in non-interactive mode

@@ -254,6 +272,24 @@ func TestLoginMfaGenerateTOTPRoleTest(t *testing.T) {
t.Fatalf("MFA failed: %v", err)
}

if secret.Auth == nil || secret.Auth.ClientToken == "" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by these test changes - are they related to the new rest of the PR? It looks like we're just checking in the audit log to see if the explicit write we did to sys/mfa/validate resulted in an audit record.

Copy link
Contributor Author

@hghaf099 hghaf099 Feb 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I just did not want to push another PR for it. I have made a note in the PR description about it.

Copy link
Collaborator

@ncabatoff ncabatoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@hghaf099 hghaf099 merged commit 53519c0 into main Feb 24, 2022
@hghaf099 hghaf099 deleted the cli-mfalogin-imp branch February 24, 2022 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants