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
Cluster Setup doesn't set consistent admin user #1781
Comments
Not sure if this is useful, but I wrote a function to set admin passwords that could maybe be used and/or repurposed? The idea is that it takes a while for the first, locally set password to get hashed, so it waits until the hashing occurs, and only then sets the same Username, and HashedPassword on the other nodes in the cluster: set_cluster_admin_password(Username, Password) ->
Section = "admins",
ok = config:set(Section, Username, Password),
Condition = fun() ->
case config:get(Section, Username, Password) of
Password ->
wait;
Hashed ->
{ok, Hashed}
end
end,
{ok, HashedPassword} = test_util:wait(Condition, 100, 5),
{Results, []} = rpc:multicall(config, set,
[Section, Username, HashedPassword]),
true = lists:all(fun(ok) -> true end, Results),
{Passwords, []} = rpc:multicall(config, get, [Section, Username]),
true = lists:all(fun(P) -> P =:= HashedPassword end, Passwords),
HashedPassword. This would probably need some better error handling to be viable, but it seems to work under normal conditions:
|
I'm not familiar with fauxton: does it use the _config endpoint to configure admin users? If so, it would seem we'd need to expose a new endpoint for |
It uses the cluster setup endpoints, which do correctly set admins remotely, not via the config endpoint. See https://github.com/apache/couchdb/tree/master/src/setup They just don't sync salts. |
To sync salts, we could modify this code something like this: diff --git a/src/couch/src/couch_passwords.erl b/src/couch/src/couch_passwords.erl
index baf78f5d5..403b057ba 100644
--- a/src/couch/src/couch_passwords.erl
+++ b/src/couch/src/couch_passwords.erl
@@ -41,18 +41,24 @@ hash_admin_password(ClearPassword) when is_binary(ClearPassword) ->
hash_admin_password(Scheme, ClearPassword).
hash_admin_password("simple", ClearPassword) -> % deprecated
- Salt = couch_uuids:random(),
+ Salt = salt(),
Hash = crypto:hash(sha, <<ClearPassword/binary, Salt/binary>>),
?l2b("-hashed-" ++ couch_util:to_hex(Hash) ++ "," ++ ?b2l(Salt));
hash_admin_password("pbkdf2", ClearPassword) ->
Iterations = config:get("couch_httpd_auth", "iterations", "10000"),
- Salt = couch_uuids:random(),
+ Salt = salt(),
DerivedKey = couch_passwords:pbkdf2(couch_util:to_binary(ClearPassword),
Salt ,list_to_integer(Iterations)),
?l2b("-pbkdf2-" ++ ?b2l(DerivedKey) ++ ","
++ ?b2l(Salt) ++ ","
++ Iterations).
+salt() ->
+ case config:get("couch_httpd_auth", "salt") of
+ undefined -> couch_uuids:random();
+ Salt -> list_to_binary(Salt)
+ end.
+
-spec get_unhashed_admins() -> list().
get_unhashed_admins() ->
lists:filter( and then fauton could be modified to obtain a uuid from a node
and then set the config option on each node separately via
after which the way it's currently setting the admin passwords should start yielding the same hashes. I might be worried that having the salt in the config file is a security concern, but then I notice that we already store the salt with each admin user already
|
@jaydoane But that breaks the entire cluster setup wizard approach, doesn't it? |
@wohali Hmm, I thought it kept the current approach mostly the same, and just added a couple additional requests beforehand to sync the salt on all nodes. In what way do you think it breaks the setup wizard approach? I suppose |
@jaydoane setup wizard can be fully run from the CLI. does your workflow work WITHOUT Fauxton and WITHOUT additional API calls? that's the point of the setup wizard. See http://docs.couchdb.org/en/latest/setup/cluster.html#the-cluster-setup-api I know for a fact people use this in Chef recipes et. al. and expect it to do all the setup for them. This ticket was specifically to fix that API endpoint so it did all the things... |
@wohali ok, got it -- thanks for patiently explaining the requirements. It seems like your initial suggestion of passing the salt in with the |
Ideally I'd like it to set the admin password on the "coordinator" node, then re-use that salt on subsequent nodes added to the cluster. This way you'd never have to pass in the salt. |
It seems that we can sync the salt from the coordinator node at the end of setup, because it's only then, after the other nodes have been added, that all nodes will become connected. Similarly, we can sync the admin users from the coordinating node at the same time. It turns out these operations are pretty much independent, and syncing the salt is only really necessary for subsequently added admin users to have the same salt and hashed values (which still seems valuable). In any case, I have a working proof of concept which still needs some error handling before it's worthy of review. |
I had this fixed a while ago in this commit: apache/couchdb-setup@54623ce The scenario is first-time setup: the admin us created on the coordinating note, after that, only the password hash which includes the salt, is sent to the other nodes. I’m not sure how this plays with adding new nodes to existing clusters, but that’s so far been out of scope for the setup wizard. |
@janl I'm afraid this is still a bug. In this example,
Our instructions then tell users to set an initial admin username and password on each node independently. In this example, I don't set a password on node 2, but I do on nodes 1 and 3:
Note the different salts - at this point, this is expected. Now I proceed to join the nodes into the cluster. Node 2 goes as expected:
But node 3 doesn't work:
Oops, I thought, I forgot to include the Even specifying the value doesn't change the result:
OK, I thought, maybe I should start with random logins per node and then create a new, different admin user using the setup wizard. Same initial config setup: 3 nodes, unconfigured.
Set up a unique admin user per node with the cluster setup API:
Now let's try and create a unified
Something's broken - either our documentation is wrong, the code is wrong, or both. |
Docs then, the wizard expects to init the admin user on all nodes. |
@janl I want to make sure I understand this correctly. The correct workflow is:
My example shows that even setting the same admin user on all nodes first with different salts doesn't allow the cluster setup wizard to forcibly fix the salt on all nodes. |
If password salt is not configured, randomly generate one and sync it also. Fixes apache#1781
It sounds like there's still some uncertainty about how admin passwords should be set, but I can confirm what @wohali observes: the way setup is currently being used (in e.g. dev/run) does not result in admin passwords with the same hash, nor is it possible to have the same salt on all nodes since it is a new random number each time a password gets hashed. I opened #1803 in an attempt to solve both of these issues without changing the setup API. |
Commenting on @wohali's examples:
The docs specify that the
But the command you show is
which is the same "enable_cluster" action as used previously on nodes For the second example using different admin users, the docs seem fairly clear to me that it should actually be the same admin user for each node, so I wouldn't expect that to work. So, here's my simple minded summary of how we expect users to set up a cluster:
At this point, we expect the salts to differer on all nodes. One thing that's confusing about the docs is that they specify using a username:password in those commands, but that would not work if no admin passwords have been configured in e.g. local.ini. Maybe we should remove those creds from the docs if we're assuming no previously configured admins?
Note that we're using the admin creds set in previous "enable_cluster" actions
By extending the functionality of this request we could sync the admin passwords configured in the "enable_cluster" requests. However, if we don't also configure a common salt among nodes, subsequent admin users created with e.g. |
So there's 2 things you've left unaddressed here that I think need to be explained before I can discuss your response.
|
Taking a step back for a sec, the docs definitely seem confusing on a couple points: First, they say "On each node we need to run the following command to set up the node:"
but then a few paragraphs later it says: "To join a node to the cluster, run these commands for each node you want to add:"
So, the first paragraph implies each node separately needs "enable_cluster" run on it (and also that is how dev/run currently does it), while the second implies you can actually make all setup requests via the coordinator node. However, perhaps the most significant difference between "direct" and "remote" cluster enabling, is that the latter uses the password hash, which I finally understand is how @janl claims that synced password hashes are already fixed. But since it only works for "remote" cluster enabling, is not well documented, and doesn't sync hashes for admin users added subsequent to cluster setup, it could perhaps still use some improvement. Anyway, to try to address @wohali's questions:
It appears that we're trying to handle a situation where known admin creds may already exist on the nodes. In that case, we'd need to use those creds either in a basic auth header if we're making direct requests, or setting them as
That is my understanding as well.
I think they could.
I assume the idea is that the remote creds (and basic auth header for coordinator) are to be used for existing admin user(s), if any, but the "username" and "password" fields are for a single, new admin user common to all nodes. I think this interpretation is supported by how the "remote" enable_cluster uses the existing admin user's hash.
I think I answered that already. Please LMK though if it's not clear.
According to this we should treat anything other than a 200 as an error. However, you will note that we only handle one kind of error here |
So we have a few bugs here:
|
the _cluster_setup endpoint expects that nodes have no admin users set at all. |
Hmm, but the docs say "The settings we recommend you set now, before joining the nodes into a cluster, are: ... At least one server administrator user (and password)" Also, these docs show admin creds being used e.g. |
Im very confused with docs, tried to set up cluster few times and it does not work as its described. When I dont set admin user in local.ini, my couchDB server does not even start, so I cant start configuring it via API. I followed @jaydoane manual for setting 3 node couchdb1/2/3 and when I do at the end:
Cluster looks like its working, but _cluster_setup endpoint is telling me its single_node, not cluster. Is there some magic trick for getting result: "cluster_finished" |
I finally found the reason.
After removing this file, I get |
Similar to #1752, if you use the cluster setup wizard to create admin users on new nodes in the cluster, the created admin user will not use an identical salt on every node, meaning Fauxton fails to obtain a valid
_session
unless you manually distribute the ini file[admins]
user yourself using a config management tool.Expected Behavior
Setup wizard creates a real server admin user that is usable from Fauxton immediately.
Current Behavior
Setup wizard creates an admin user that cannot be load balanced because the salt is different.
Possible Solution
Pass the salt along as part of the cluster setup API endpoint?
/cc @janl
The text was updated successfully, but these errors were encountered: