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

sensuctl does not provide a way to get the value of a password for a user #1437

Closed
ghoneycutt opened this issue May 3, 2018 · 15 comments · Fixed by #2278
Closed

sensuctl does not provide a way to get the value of a password for a user #1437

ghoneycutt opened this issue May 3, 2018 · 15 comments · Fixed by #2278
Assignees
Milestone

Comments

@ghoneycutt
Copy link

Configuration management tools need both get and set methods to ensure idempotency. We do a get to see if the system is in the desired state and if not, then do a set. If there is no get, then the set always runs, which is not idempotent.

sensuctl user list does not have a way to get the password, so there is no idempotent way to set the password.

Expected Behavior

sensuctl user list has a way of showing the actual password or a hashed password. This way it can be matched against desired state and the configuration management tool can decide if the password needs to be updated.

Current Behavior

sensuctl user list does not allow you to see the current state with regards to a user's password.

Possible Solution

Output a sha256 hash of the password.
Only allow the admin role to do so.

Context

This is needed for configuration management tools to act in an idempotent way.

Your Environment

  • Sensu version used (sensuctl, sensu-backend, and/or sensu-agent):

sensu-ctl version dev-nightly#cc2ded6, build cc2ded623f0646610c0d3135430544dc2993169b, built 2018-05-03T09:26:06+0000

  • Installation method (packages, binaries, docker etc.): packages

  • Operating System and version (e.g. Ubuntu 14.04): EL7

@ghoneycutt
Copy link
Author

CC: @treydock

@treydock
Copy link
Contributor

Exposing the bcrypt hash could be sufficient and something we can use in Ruby and thus Puppet. Not having to rely on bcrypt in Puppet would be super handy but looks like sensu-go stores passwords hashed with bcrypt.

2.4.1 :005 > BCrypt::Password.new("$2a$10$lFktTbaZf20GhybITpa4uebwpw2sv4YTs2aqFeVfuClvBjRBAjH26") == "P@ssw0rd!"
 => true
2.4.1 :006 > BCrypt::Password.new("$2a$10$lFktTbaZf20GhybITpa4uebwpw2sv4YTs2aqFeVfuClvBjRBAjH26") == "foobar"
 => false

@echlebek
Copy link
Contributor

We don't actually store the user's password, only the hash, as you note. I don't think we would consider storing plaintext passwords, but we could report the hash for admins.

I think from a security standpoint it might be more desirable to consider the password "changed" no matter what the current state is, but I suppose in this case, exposing the hash for admin is pretty low-risk.

@ghoneycutt
Copy link
Author

To be clear, we agree that plain text passwords should not be stored. We are looking for a hash that we can both read and easily generate.

When you say it might be more desirable to consider the password "changed" no matter what the current state is, what do you mean?

@echlebek
Copy link
Contributor

In the very rare use case where the sensu administrator does not have read access to the etcd store, retrieving the password hash, or even reporting if the password has not changed, could be seen as a security vulnerability.

Exposing the hash could in theory allow someone to crack the password of a user. Right now, that can be locked down by making sure that the sensu admin user doesn't have access to the raw etcd store.

To be clear: I highly doubt this will actually be the case, so I'm in favour of exposing the hash.

@treydock
Copy link
Contributor

Let me know if this warrants a new issue but would be handy if sensuctl configure allowed passing a bcrypt hash like --password-hash '$1$somehash' instead of passing --password. We're contemplating only dealing with bcrypt hashes and not requiring people to feed plain text passwords into the Puppet module. This would remove the need for the Puppet code to depend on bcrypt rubygem which requires extra dependencies to build.

@echlebek
Copy link
Contributor

echlebek commented Jul 1, 2018

@treydock, see #1697 which is intended to support this use case via sensuctl create. Would that work for you?

@treydock
Copy link
Contributor

treydock commented Jul 1, 2018

@echlebek Passing the hash with sensuctl create would be half of what would be needed. In order for the same code in Puppet to handle both sensuctl create and the necessary sensuctl configure for admin password changes, both would have to accept the hash. We could technically do the sensuctl configure using a plain text password in Puppet code (Exec) and not Ruby provider but that's less ideal.

@echlebek
Copy link
Contributor

echlebek commented Jul 6, 2018

@treydock I see. What would be the ideal mechanism here? A parameter for sensuctl configure? A configuration file in $HOME? Environment variables? Something else?

@portertech
Copy link
Contributor

@echlebek we also need a sensuctl subcommand to create and output a password hash for a password string for consistency across platforms.

@echlebek
Copy link
Contributor

echlebek commented Jul 6, 2018

@portertech yep, see #1768

@treydock
Copy link
Contributor

treydock commented Jul 6, 2018

@echlebek Ideally we could do something like sensuctl configure -n --url http://127.0.0.1:8080 --username admin --password-hash $1$bcrypthash where --password-hash could be used in place of the current --password argument. This is basically what we would do:

# bootstrap once
sensuctl configure -n --url http://127.0.0.1:8080 --username admin --password P@ssw0rd!

# Ruby Puppet provider executes similar commands to use non-default password and/or change admin password
cat > /tmp/user.json <<EOF
{
  "type": "User",
  "spec": {
     "name": "admin",
     "password_hash": "$1$bcrypthash",
     "roles": ["admin"],
     "disabled": false
  }
}
EOF
sensuctl create -f /tmp/user.json
sensuctl configure -n --url http://127.0.0.1:8080 --username admin --password-hash $1$bcrypthash

@obfuscurity obfuscurity changed the title sensuctl does not provider a way to get the value of a password for a user sensuctl does not provide a way to get the value of a password for a user Sep 12, 2018
@portertech
Copy link
Contributor

portertech commented Nov 1, 2018

Sensu Engineering has a few ideas:

  1. Store and expose the revision of the User object
  2. Provide an API endpoint to test credentials
  3. Return a flag indicating if the User object changed

@treydock
Copy link
Contributor

treydock commented Nov 1, 2018

Puppet operates on state so the only one that would work with Puppet is 2, testing the credentials passed to Puppet actually work. The issue with 2 is that one trick we use in Puppet is prefetching where a single command fetches the state for all objects before evaluating the puppet resources that are defined. This saves time and allows for purging, meaning unmanaged resources can be removed. This is actually very attractive for users resource, allowing Puppet to remove unmanaged sensu users from an instance of sensu-backend. The only way to do this would be to expose all users and their attributes similar to things like checks.

So to summarize, we can make 2 work but it's far from ideal. For Puppet the most ideal solution is exposing the bcrypt hash.

@treydock
Copy link
Contributor

I built sensu-go from source and tested some prototype Puppet code and #2278 will work for Puppet and still allow helpful features like removing unmanaged users.

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 a pull request may close this issue.

6 participants