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

Avoid leaking passwords into shell history and audits events by supporting reading passwords from stdin #881

Merged
merged 8 commits into from
Nov 17, 2021

Conversation

patdowney
Copy link
Contributor

@patdowney patdowney commented Oct 10, 2021

Proposed changes

Jira: CLOUDP-106015

closes #882

Adds a --passwordStdin flag to the appropriate mongocli commands in order to avoid the specified password showing up in terminal history or system audit records by allowing it to be passed in via stdin.

This will allow things like

$ vault read -field=value my/path/to/secret | mongocli atlas dbuser create --username ${USER} --role clusterMonitor,backup --projectId ${PROJECT} --passwordStdin

Checklist

  • I have signed the MongoDB CLA
  • I have added tests that prove my fix is effective or that my feature works
  • I have added any necessary documentation (if appropriate)
  • I have updated e2e/E2E-TESTS.md (if a new command or e2e test has been added)
  • I have run make fmt and formatted my code

@patdowney patdowney requested a review from a team as a code owner October 10, 2021 08:01
@patdowney patdowney requested review from a team and fmenezes October 10, 2021 08:01
@gssbzn
Copy link
Collaborator

gssbzn commented Oct 11, 2021

Hi @patdowney first thanks for the contribution but given the scope of it would you mind opening an issue first to discuss the feature?

There are a couple of things it would be nice to agree first before focusing on the code details.

Main one I want to call out, many of the commands you are changing would read input from stdin when the --password is omitted but I guess you're being affected by AlecAivazis/survey#328, I think it would be better to fix the issue at the root but we could discuss alternatives in an issue in this repo if you prefer

@patdowney
Copy link
Contributor Author

@gssbzn Absolutely. I've raised #882 Re: AlecAivazis/survey#328 - fixing that issue looks like it would help with my use case, although their FAQ does say "This means that reading from piped stdin or writing to piped stdout is not supported, and likely to break your application in these situations" so I'm not sure when that issue will be addressed!

This patch should not change any existing behaviour, so not passing in --password will still end up with the user being prompted in a user friendly way.

@gssbzn
Copy link
Collaborator

gssbzn commented Oct 18, 2021

thanks for the issue, let's discuss these changes there

@gssbzn
Copy link
Collaborator

gssbzn commented Oct 28, 2021

Hi @patdowney I se you've done some changes based on my comments from #882, is this PR ready for review?

@patdowney
Copy link
Contributor Author

Yes please!

@@ -0,0 +1,15 @@
package prompt
Copy link
Collaborator

@gssbzn gssbzn Nov 4, 2021

Choose a reason for hiding this comment

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

let's please add

Suggested change
package prompt
//go:build unit
// +build unit
package prompt

Copy link
Collaborator

@gssbzn gssbzn left a comment

Choose a reason for hiding this comment

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

sorry for the delay on this

one initial things that's causing our internal CI to fail, the new files are missing the copyright header, you can fix this by running make addcopy

Copy link
Collaborator

@gssbzn gssbzn left a comment

Choose a reason for hiding this comment

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

another failure from our CI

 [2021/11/03 10:51:51.817] FAILURE: Failed ()
 [2021/11/03 10:51:51.817] === RUN   TestDBUsers/Create
 [2021/11/03 10:51:51.817]     dbusers_test.go:65:
 [2021/11/03 10:51:51.817]         	Error Trace:	dbusers_test.go:202
 [2021/11/03 10:51:51.817]         	            				dbusers_test.go:65
 [2021/11/03 10:51:51.817]         	Error:      	Not equal:
 [2021/11/03 10:51:51.817]         	            	expected: "passW0rd"
 [2021/11/03 10:51:51.817]         	            	actual  : ""
 [2021/11/03 10:51:51.817] 
 [2021/11/03 10:51:51.817]         	            	Diff:
 [2021/11/03 10:51:51.817]         	            	--- Expected
 [2021/11/03 10:51:51.817]         	            	+++ Actual
 [2021/11/03 10:51:51.817]         	            	@@ -1 +1 @@
 [2021/11/03 10:51:51.817]         	            	-passW0rd
 [2021/11/03 10:51:51.817]         	            	+
 [2021/11/03 10:51:51.817]         	Test:       	TestDBUsers/Create
 [2021/11/03 10:51:51.817]     --- FAIL: TestDBUsers/Create (0.10s)
 [2021/11/03 10:51:51.884] FAILURE: Failed ()
 [2021/11/03 10:51:51.884] === RUN   TestDBUsers/CreatePasswordStdin
 [2021/11/03 10:51:51.884]     dbusers_test.go:83:
 [2021/11/03 10:51:51.884]         	Error Trace:	dbusers_test.go:194
 [2021/11/03 10:51:51.884]         	            				dbusers_test.go:83
 [2021/11/03 10:51:51.884]         	Error:      	Received unexpected error:
 [2021/11/03 10:51:51.884]         	            	exit status 1
 [2021/11/03 10:51:51.884]         	Test:       	TestDBUsers/CreatePasswordStdin
 [2021/11/03 10:51:51.884]     dbusers_test.go:83: unexpected error: invalid character 'E' looking for beginning of value
 [2021/11/03 10:51:51.884]     --- FAIL: TestDBUsers/CreatePasswordStdin (0.04s)

@gssbzn
Copy link
Collaborator

gssbzn commented Nov 4, 2021

Also before we can accept your contribution we need you to sign our CLA

@patdowney
Copy link
Contributor Author

Thanks @gssbzn . I'll address your comments, hopefully this weekend. I thought I'd already signed the CLA?

@gssbzn
Copy link
Collaborator

gssbzn commented Nov 4, 2021

I thought I'd already signed the CLA?

I could not find your github username on our database, if you can double check if you did that'd be great

@patdowney
Copy link
Contributor Author

Think I've figured it out, I signed the form but didn't click the further confirmation link that's sent afterwards. Will take care of that this weekend as well

@patdowney
Copy link
Contributor Author

Actually, have just found the confirmed email. I signed it on 2021-10-02, GitHub username on the form is dioadconsulting maybe I got that bit wrong

@gssbzn
Copy link
Collaborator

gssbzn commented Nov 4, 2021

GitHub username on the form is dioadconsulting maybe I got that bit wrong

Thanks that was it, I can see dioadconsulting, would you mind signing again with the correct username?

@gssbzn
Copy link
Collaborator

gssbzn commented Nov 8, 2021

Thanks again for all the changes, code looks good I have some recommendations on the tests and I'm waiting for our CI ro run to make sure there's no other thing to look at

Remove assertion on BindPassword property from response. It doesn't exist.
@colm-quinn
Copy link
Collaborator

This is failing the linting check currently:

  Error: paramTypeCombine: func(t *testing.T, cliPath string, projectID string) could be replaced with func(t *testing.T, cliPath, projectID string) (gocritic)

I'd recommend running those checks locally with make lint and/or make fix-lint to catch the issues as you are committing changes.

@@ -131,7 +139,7 @@ func (opts *CreateOpts) validate() error {
return errors.New("missing role for the user")
}

if opts.isExternal() && opts.password != "" {
if opts.isExternal() && (opts.password != "") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

[q/np] Do we need the extra brackets here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks @colm-quinn. Addressed in latest.

Copy link
Collaborator

@andreaangiolillo andreaangiolillo left a comment

Choose a reason for hiding this comment

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

LGTM. You just need to fix the lint issue.

Comment on lines +71 to +87
func (opts *SaveOpts) Prompt() error {
if opts.bindPassword != "" {
return nil
}

if !opts.IsTerminalInput() {
_, err := fmt.Fscanln(opts.InReader, &opts.bindPassword)
return err
}

prompt := &survey.Password{
Message: "Password:",
}

return survey.AskOne(prompt, &opts.bindPassword)
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

[nit] I think we could add this function under InputOpts and pass the password as an input parameter so that we can reuse this piece of code. Then you can call this function in any commands that require this prompt message

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@andreaangiolillo - is this a change you'd like me to introduce as part of this PR?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It is up to you. We can add this improvement in another PR if you want ; )

if err := json.Unmarshal(resp, &configuration); a.NoError(err) {
a.Equal(ldapHostname, configuration.LDAP.Hostname)
}
testLDAPSaveCmd(t, cmd)
Copy link
Collaborator

Choose a reason for hiding this comment

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

 [2021/11/15 15:41:25.385] FAILURE: Failed ()
 [2021/11/15 15:41:25.385] === RUN   TestLDAPWithFlags/Save
 [2021/11/15 15:41:25.385]     ldap_test.go:132:
 [2021/11/15 15:41:25.385]         	Error Trace:	ldap_test.go:270
 [2021/11/15 15:41:25.385]         	            				ldap_test.go:132
 [2021/11/15 15:41:25.385]         	Error:      	Not equal:
 [2021/11/15 15:41:25.385]         	            	expected: "admin"
 [2021/11/15 15:41:25.385]         	            	actual  : ""
 [2021/11/15 15:41:25.385] 
 [2021/11/15 15:41:25.385]         	            	Diff:
 [2021/11/15 15:41:25.385]         	            	--- Expected
 [2021/11/15 15:41:25.385]         	            	+++ Actual
 [2021/11/15 15:41:25.385]         	            	@@ -1 +1 @@
 [2021/11/15 15:41:25.385]         	            	-admin
 [2021/11/15 15:41:25.385]         	            	+
 [2021/11/15 15:41:25.385]         	Test:       	TestLDAPWithFlags/Save
 [2021/11/15 15:41:25.385]     --- FAIL: TestLDAPWithFlags/Save (0.09s)

passwordStdin := bytes.NewBuffer([]byte(ldapBindPassword))
cmd.Stdin = passwordStdin

testLDAPSaveCmd(t, cmd)
Copy link
Collaborator

Choose a reason for hiding this comment

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


 [2021/11/15 15:41:25.641] FAILURE: Failed ()
 [2021/11/15 15:41:25.641] === RUN   TestLDAPWithStdin/Save
 [2021/11/15 15:41:25.641]     ldap_test.go:218:
 [2021/11/15 15:41:25.641]         	Error Trace:	ldap_test.go:270
 [2021/11/15 15:41:25.641]         	            				ldap_test.go:218
 [2021/11/15 15:41:25.641]         	Error:      	Not equal:
 [2021/11/15 15:41:25.641]         	            	expected: "admin"
 [2021/11/15 15:41:25.641]         	            	actual  : ""
 [2021/11/15 15:41:25.641] 
 [2021/11/15 15:41:25.641]         	            	Diff:
 [2021/11/15 15:41:25.641]         	            	--- Expected
 [2021/11/15 15:41:25.641]         	            	+++ Actual
 [2021/11/15 15:41:25.641]         	            	@@ -1 +1 @@
 [2021/11/15 15:41:25.641]         	            	-admin
 [2021/11/15 15:41:25.641]         	            	+
 [2021/11/15 15:41:25.641]         	Test:       	TestLDAPWithStdin/Save
 [2021/11/15 15:41:25.641]     --- FAIL: TestLDAPWithStdin/Save (0.10s)

passwordStdin := bytes.NewBuffer([]byte("passW0rd"))
cmd.Stdin = passwordStdin

testCreatePasswordCmd(t, cmd)
Copy link
Collaborator

@gssbzn gssbzn Nov 15, 2021

Choose a reason for hiding this comment

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

[2021/11/15 15:28:14.823] FAILURE: Failed ()
 [2021/11/15 15:28:14.823] === RUN   TestDBUsers/CreatePasswordStdin
 [2021/11/15 15:28:14.823]     dbusers_test.go:92: unexpected error: exit status 1, resp: Error: PUT https://cloud-dev.mongodb.com/api/public/v1.0/groups/61927b10ab680d0601bf033a/automationConfig: 400 (request "") Invalid config: Each auth.usersWanted must have a unique user id. Duplicate found: user-126@admin
 [2021/11/15 15:28:14.823]     --- FAIL: TestDBUsers/CreatePasswordStdin (0.15s)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah, same stuff as the atlast tests, will take a look at pulling these out into TestDBUsersWithFlags and TestDBUsersWithStdin too.

Copy link
Collaborator

@gssbzn gssbzn left a comment

Choose a reason for hiding this comment

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

Some of the E2E tests are still failing, LDAP and cloud manager/ops manager dbusers

Copy link
Collaborator

@gssbzn gssbzn left a comment

Choose a reason for hiding this comment

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

🎉 thanks so much @patdowney
Tests are looking good and I can confirm the CLA has been signed, we'll be merging this shortly

Copy link
Collaborator

@colm-quinn colm-quinn left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for those changes and working through all the comments - this is a great contribution!

@gssbzn
Copy link
Collaborator

gssbzn commented Nov 17, 2021

Internal ticket: CLOUDP-106015

@gssbzn gssbzn merged commit db352de into mongodb:master Nov 17, 2021
@patdowney
Copy link
Contributor Author

Great 👍 Thanks for your patience!

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.

Avoid leaking passwords into shell history and audits events by supporting reading passwords from stdin
5 participants