Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2535)

Issue 21000044: state/unit/machine/user: change password hashes

Can't Edit
Can't Publish+Mail
Start Review
Created:
10 years, 6 months ago by jameinel
Modified:
10 years, 6 months ago
Reviewers:
mp+193667, john2, wallyworld, rog
Visibility:
Public.

Description

state/unit/machine/user: change password hashes This is a follow up to my previous PasswordHash changes, making it a more complete step. 1) PasswordHash is split into 3 functions: UserPasswordHash(password, salt) passwordhash CompatPasswordHash(password) passwordhash { return UserPasswordHash(password, oldDefaultSalt) } AgentPasswordHash(password) passwordHash, error 2) UserPasswordHash does the same 8192 rounds of pbkdf2 hashing to ensure that it is hard to brute force a user's password. On top of that, it requires a "salt" value. state/User grows an added field PasswordSalt. Whenever we call User.SetPassword we generate a salt and use that to compute the password hash. For compatibility, if User.PasswordSalt is the empty string, we use the CompatPasswordHash which sets the salt to the old hard-coded salt. I chose to use a different function to make it clear that we don't really want to support empty salts. 3) CompatPasswordHash is just a thin wrapper over UserPasswordHash. It should always generate the same hash value that utils.PasswordHash used to generate. I changed the name just to make it clear. Though Bootstrap still uses this directly as the way to hide the real plaintext password. 4) User.PasswordValid(password) knows how to check both ways for compatibility, and if it sees that the saved hash was not salted, it calls SetPassword() immediately to set a salt and regenerate the password hash. 5) For Machine and Unit agents, we change their hash function to just be a simple SHA-512 of the password. We don't bother with a salt or with iterated pbkdf2. This is because we know that agents have very high entropy passwords (utils.RandomPassword uses 18 bytes of entropy or 2^144). This is not really feasible to brute force, so there isn't really a point to salt or iterate. As part of this change, AgentPasswordHash(string) string, error can return an error if it appears the password might not have enough entropy (for now we just check the length of the password). That way someone can't accidentally get rooted because they set the machine-0 agent password to "foo". This probably had the widest effect as we had a lot of tests that set a simple password just so we could login as that agent, but we just change it so we use utils.RandomPassword in all of those places. As mentioned before, this is a big performance win when scaling up to thousands of agents. Timing shows UserPasswordHash takes about 80ms, while AgentPasswordHash takes about 8us. PasswordHash was dominating the time it took for the system to recover after restarting the API machine. 6) Similar to User.PasswordValid, Machine.PasswordValid and Unit.PasswordValid will do a fast check using AgentPasswordValid, and if that fails, they will fall back to the slow CompatPasswordValid. If they find the passwordhash is a compat value, they reset the value to the fast-path value. 7) I looked at removing the FastInsecureHash flag (since we've split the hashes we create). However, with it unset I found the 'state/...' tests took >4min while with it set they still took more like 3min. So it still shaves 25% of the test suite time. https://code.launchpad.net/~jameinel/juju-core/faster-passwords/+merge/193667 (do not edit description out of merge proposal)

Patch Set 1 #

Total comments: 19

Patch Set 2 : state/unit/machine/user: change password hashes #

Total comments: 14

Patch Set 3 : state/unit/machine/user: change password hashes #

Patch Set 4 : state/unit/machine/user: change password hashes #

Unified diffs Side-by-side diffs Delta from patch set Stats (+577 lines, -165 lines) Patch
A [revision details] View 1 2 3 1 chunk +2 lines, -0 lines 0 comments Download
M agent/bootstrap.go View 1 2 1 chunk +7 lines, -1 line 0 comments Download
M agent/bootstrap_test.go View 1 2 2 chunks +2 lines, -2 lines 0 comments Download
M cmd/jujud/bootstrap_test.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M cmd/jujud/machine_test.go View 1 1 chunk +1 line, -1 line 0 comments Download
M cmd/jujud/unit_test.go View 1 1 chunk +1 line, -1 line 0 comments Download
M environs/cloudinit.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M environs/cloudinit_test.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M juju/conn.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M juju/conn_test.go View 1 2 2 chunks +2 lines, -2 lines 0 comments Download
M juju/testing/conn.go View 1 3 chunks +8 lines, -3 lines 0 comments Download
M provider/dummy/environs.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M provider/local/environ.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M state/api/agent/machine_test.go View 1 1 chunk +4 lines, -2 lines 0 comments Download
M state/api/agent/unit_test.go View 1 2 chunks +5 lines, -2 lines 0 comments Download
M state/api/deployer/deployer_test.go View 1 2 chunks +8 lines, -4 lines 0 comments Download
M state/api/provisioner/provisioner_test.go View 1 2 chunks +5 lines, -2 lines 0 comments Download
M state/api/uniter/uniter_test.go View 1 2 chunks +6 lines, -3 lines 0 comments Download
M state/apiserver/agent/agent_test.go View 1 2 chunks +16 lines, -4 lines 0 comments Download
M state/apiserver/client/api_test.go View 1 2 chunks +3 lines, -2 lines 0 comments Download
M state/apiserver/deployer/deployer_test.go View 1 3 chunks +7 lines, -7 lines 0 comments Download
M state/apiserver/logger/logger_test.go View 1 1 chunk +0 lines, -2 lines 0 comments Download
M state/apiserver/machine/agent_test.go View 1 2 chunks +4 lines, -4 lines 0 comments Download
M state/apiserver/provisioner/provisioner_test.go View 1 2 chunks +17 lines, -4 lines 0 comments Download
M state/apiserver/server_test.go View 1 6 chunks +20 lines, -9 lines 0 comments Download
M state/apiserver/upgrader/upgrader_test.go View 1 1 chunk +0 lines, -2 lines 0 comments Download
M state/apiserver/utils.go View 1 1 chunk +1 line, -1 line 0 comments Download
M state/export_test.go View 1 2 chunks +22 lines, -0 lines 0 comments Download
M state/machine.go View 1 2 1 chunk +35 lines, -4 lines 0 comments Download
M state/machine_test.go View 1 1 chunk +6 lines, -0 lines 0 comments Download
M state/state_test.go View 1 2 2 chunks +56 lines, -9 lines 0 comments Download
M state/unit.go View 1 2 1 chunk +35 lines, -4 lines 0 comments Download
M state/unit_test.go View 1 1 chunk +6 lines, -0 lines 0 comments Download
M state/user.go View 1 2 4 chunks +36 lines, -7 lines 0 comments Download
M state/user_test.go View 1 2 3 chunks +82 lines, -7 lines 0 comments Download
M testing/mgo.go View 1 2 1 chunk +1 line, -1 line 0 comments Download
M utils/password.go View 1 2 3 4 chunks +42 lines, -7 lines 0 comments Download
A utils/password_test.go View 1 2 1 chunk +91 lines, -0 lines 0 comments Download
M utils/trivial_test.go View 1 1 chunk +0 lines, -41 lines 0 comments Download
M worker/provisioner/provisioner_test.go View 1 1 chunk +4 lines, -2 lines 0 comments Download
M worker/uniter/charm/charm_test.go View 1 2 chunks +5 lines, -2 lines 0 comments Download
M worker/uniter/context_test.go View 1 2 chunks +8 lines, -5 lines 0 comments Download
M worker/uniter/filter_test.go View 1 2 chunks +6 lines, -3 lines 0 comments Download
M worker/uniter/relationer_test.go View 1 3 chunks +11 lines, -6 lines 0 comments Download
M worker/uniter/uniter_test.go View 1 2 chunks +6 lines, -3 lines 0 comments Download

Messages

Total messages: 10
jameinel
Please take a look.
10 years, 6 months ago (2013-11-01 21:53:46 UTC) #1
john2
On 2013/11/01 21:53:46, jameinel wrote: > Please take a look. To put it another way, ...
10 years, 6 months ago (2013-11-02 04:42:09 UTC) #2
wallyworld
LGTM with some clarifications sought https://codereview.appspot.com/21000044/diff/1/state/export_test.go File state/export_test.go (right): https://codereview.appspot.com/21000044/diff/1/state/export_test.go#newcode175 state/export_test.go:175: return fmt.Errorf("Authenticator has not ...
10 years, 6 months ago (2013-11-04 03:35:09 UTC) #3
rog
Great, thanks a lot for doing this! LGTM modulo the below (the only thing I ...
10 years, 6 months ago (2013-11-04 10:17:36 UTC) #4
jameinel
I did end up doing these things, but because of the discussion about Salt, etc, ...
10 years, 6 months ago (2013-11-05 07:16:30 UTC) #5
jameinel
Please take a look.
10 years, 6 months ago (2013-11-05 14:17:21 UTC) #6
rog
An excellent direction, thanks. Some thoughts and suggestions below. https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go File agent/bootstrap.go (right): https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go#newcode105 agent/bootstrap.go:105: ...
10 years, 6 months ago (2013-11-05 15:18:58 UTC) #7
jameinel
Please take a look. https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go File agent/bootstrap.go (right): https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go#newcode105 agent/bootstrap.go:105: if err := u.SetPasswordHash(passwordHash, ""); ...
10 years, 6 months ago (2013-11-07 07:13:30 UTC) #8
jameinel
Please take a look. https://codereview.appspot.com/21000044/diff/20001/utils/password.go File utils/password.go (right): https://codereview.appspot.com/21000044/diff/20001/utils/password.go#newcode90 utils/password.go:90: if len(password) < 24 { ...
10 years, 6 months ago (2013-11-07 08:28:38 UTC) #9
rog
10 years, 6 months ago (2013-11-07 09:37:48 UTC) #10
https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go
File agent/bootstrap.go (right):

https://codereview.appspot.com/21000044/diff/20001/agent/bootstrap.go#newcode105
agent/bootstrap.go:105: if err := u.SetPasswordHash(passwordHash, ""); err !=
nil {
On 2013/11/07 07:13:31, jameinel wrote:
> I actually left this as "". Because then it means on first login we will
> automatically generate a new salt for the Admin user.
> I *could* change the PasswordValid code to do:
> 
> if PasswordSalt != "" && PasswordSalt != CompatSalt
> 
> but honestly, just having "" as the signal that we haven't set a real salt
seems
> better to me.

I don't think we need to change the salt for existing environments. What
are the risks of someone generating a rainbow table specifically for
the very few (probably less than 50) juju environments that are upgraded
and have the old salt? Given that each juju environment has exactly
one user, what's the likelyhood of two environments sharing the same
password? And even if we *do* change the salt, given that
they need to get access to a bootstrap node to obtain the password hash,
where they can also access the original cloudinit data containing the
legacy-salted password, our new salting adds no extra security.

I'd prefer to keep the code simpler and avoid any special casing
in this respect.
Sign in to reply to this message.

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b