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

nixos/keystone: init at liberty version #20905

Merged
merged 3 commits into from
Dec 16, 2016
Merged

nixos/keystone: init at liberty version #20905

merged 3 commits into from
Dec 16, 2016

Conversation

nlewo
Copy link
Member

@nlewo nlewo commented Dec 4, 2016

Motivation for this change
Things done
  • Tested using sandboxing
    (nix.useSandbox on NixOS,
    or option build-use-sandbox in nix.conf
    on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • Linux
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

This commit introduces a nixos module for the Openstack Keystone
service. It also provides a optional bootstrap step that creates some
basic initial resources (tenants, endpoints,...).

The provided test starts Keystone by enabling bootstrapping and checks
if user creation works well.

This commit is based on initial works made by domenkozar.

@mention-bot
Copy link

@nlewo, thanks for your PR! By analyzing the history of the files in this pull request, we identified @edolstra, @joachifm and @offlinehacker to be potential reviewers.

@nlewo nlewo mentioned this pull request Dec 4, 2016
policy_file=${cfg.package}/etc/policy.json

[database]
connection = mysql://${cfg.database.user}:${cfg.database.password}@${cfg.database.host}/${cfg.database.name}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure, but maybe would be better to move all this config line as parameter instead of splitting it into smaller parts? For example keystone supports postgresql as well, in such a case user could just paste all the connection string.

In the description field there could be a link to keystone documentation. there is also example field in mkOption so you could provide one or two examples.

And probably this could be a "secret".

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@@ -629,4 +629,5 @@
./virtualisation/vmware-guest.nix
./virtualisation/xen-dom0.nix
./virtualisation/xe-guest-utilities.nix
./virtualisation/keystone.nix
Copy link
Member

Choose a reason for hiding this comment

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

IMHO, I think keystone is not about virtualization at all.
My preference would be to either:

  • move separate services to categories that match what they do
  • create sub-category in virtualisation for open stack and keep everything there, i.e.
virtualisation.openstack = {
  keystone.enable=true;
};

Copy link
Member Author

Choose a reason for hiding this comment

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

My preference is your point 2. Moreover, this is already the openstack nix packages layout.

default = false;
type = types.bool;
description = ''
Bootstrap the Keystone service by creating the service
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice to mention if the bootstrap will be done only first time or each time we deploy. I would expect that if I have bootstrap = true, the bootstrap will be done only one time but I'm not sure what is the behaviour from this description.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

type = types.str;
default = "localhost";
description = ''
The address of the public identity endpoint.
Copy link
Member

Choose a reason for hiding this comment

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

Option name says endpoint and description says address. I'm probably biased by when I think about endpoint I have URL/URI in my mind (http://example.org:25/path, tcp://127.0.0.5), when I think of address I have in my mind IP:PORT combination, eventually DNS:PORT. Would be nice to use explain better in the description what values are allowed.

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed this option a little bit to be more explicit.

# systems!
virtualisation.keystone.package = mkDefault pkgs.keystone;

services.mysql.enable = mkDefault (cfg.database.host == "localhost");
Copy link
Member

Choose a reason for hiding this comment

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

Please don't :-)
This can be done on higher level. This can be surprise (also it was not mentioned in the description), maybe somebody would like to use postgres.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done ;)

gid = config.ids.gids.keystone;
}];

systemd.services.keystone-all = {
Copy link
Member

Choose a reason for hiding this comment

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

why not just keystone?

Copy link
Member Author

Choose a reason for hiding this comment

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

The binary name is keystone-all while the binary keystone is the client. For me, it's more clear to use keystone-all since I know this is the keystone server. This is a respond to the "why" and not a respond at the question "what is the best" ;)

path = [ cfg.package pkgs.mysql pkgs.curl pkgs.pythonPackages.keystoneclient pkgs.gawk ];
wantedBy = [ "multi-user.target" ];
preStart = ''
mkdir -m 755 -p /var/lib/keystone
Copy link
Member

Choose a reason for hiding this comment

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

optionally you could have "work-dir" option as some other modules

Copy link
Member Author

Choose a reason for hiding this comment

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

This could be addressed later without any breaking changes I think.

postStart = optionalString cfg.bootstrap.enable ''
# Wait until the keystone is available for use
count=0
while ! curl -s http://localhost:35357/v2.0 > /dev/null
Copy link
Member

Choose a reason for hiding this comment

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

Probably the port could be configurable (actually I'm not sure actually if it is related to endpointPublic or not). There was no other parameter to specify listening address.

Copy link
Member

Choose a reason for hiding this comment

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

You need "--fail" option

       -f, --fail
              (HTTP)  Fail silently (no output at all) on server errors. This is mostly done to bet‐
              ter enable scripts etc to better deal with failed attempts. In normal  cases  when  an
              HTTP server fails to deliver a document, it returns an HTML document stating so (which
              often also describes why and more). This flag will prevent curl from  outputting  that
              and return error 22.

              This  method  is  not  fail-safe and there are occasions where non-successful response
              codes will slip through, especially when authentication is  involved  (response  codes
              401 and 407).

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Thanks.

# Set up the keystone's PKI infrastructure
${cfg.package}/bin/keystone-manage --config-file=${keystoneConf} pki_setup --keystone-user keystone --keystone-group keystone
'';
postStart = optionalString cfg.bootstrap.enable ''
Copy link
Member

Choose a reason for hiding this comment

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

you may consider "set -eu" to make script more robust (it will break script when there is an error or when variable is not set but used)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@@ -0,0 +1,51 @@
{ system ? builtins.currentSystem }:
Copy link
Member

Choose a reason for hiding this comment

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

very nice smoketest!

@spinus
Copy link
Member

spinus commented Dec 5, 2016

@nlewo thanks for making those changes.
The only thing now which I see problematic are the credentials in the nix store rather than in files. Other stuff looks good to me.

This commit introduces a nixos module for the Openstack Keystone
service. It also provides a optional bootstrap step that creates some
basic initial resources (tenants, endpoints,...).

The provided test starts Keystone by enabling bootstrapping and checks
if user creation works well.

This commit is based on initial works made by domenkozar.
# can be stored in the nix store, or not. A pattern is written in
# the nix store to represent the secret. The pattern can
# then be overwritten with the value of the secret at runtime.
mkSecretOption = {name, description ? ""}:
Copy link
Member

Choose a reason for hiding this comment

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

oh boy, you really like those nix store passwords, don't you :-)

Anyway, if files are working I'm ok with it.

Copy link
Member Author

Choose a reason for hiding this comment

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

We could test if the password contains '/', then use '|' as separator, and so on...

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure it's worth, even if we fix it here, some values might break the application config files itself (this is probably application specific).

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah yes, exactly...

default = "##${name}##";
description = "The pattern that represent the secret.";
};
storage = mkOption {
Copy link
Member

Choose a reason for hiding this comment

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

if you add

default = "fromFile";

I'll be more than happy.

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess this is not working. If you set this default, I guess you can not use fromNixStore anymore.
But anyway, the user have to declare these variable, and I think the name is enough explicit to inform the user its password will be store in the nix store or not.

Copy link
Member

Choose a reason for hiding this comment

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

If you set default, yes, you can use other values as well. Just without explicit set, the default is taken, that's it.
If you think that explicit decision here is better, fair enough.

# A shell script string help to replace at runtime in a file the
# pattern of a secret by its value.
replaceSecret = secretOption: filename: ''
sed -i "s/${secretOption.pattern}/${getSecret secretOption}/g" ${filename}
Copy link
Member

Choose a reason for hiding this comment

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

This can break if password contains /, but I don't have better idea what to do with it now.

Copy link
Member Author

Choose a reason for hiding this comment

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

;)
In fact, I would like to have an "easy to use" mode. If someone wants to test the module, or deploy a dev environment, he doesn't have to handle password file and manually manage its password.

@spinus
Copy link
Member

spinus commented Dec 11, 2016

Thanks for adding "passwords from files" feature.

@nlewo
Copy link
Member Author

nlewo commented Dec 11, 2016

It is strange there is not a common mechanism to handle these passwords in nixos. In fact, I'm not really fan of the way proposed here but it does the job in the context of this PR. I think we could open a topic to implement a clean and common way to do this. I haven't time on this for now.

Moreover, I tryied complex options definitions and submodule and either option type seems to be fragile, especially with default values.

@spinus
Copy link
Member

spinus commented Dec 11, 2016

@nlewo It's not strange, the discussion is still going I think (check one of the first issues on github about private nix store entries), on the other front, recently, the security team is forming, all this stuff is slowly happening.

Good stuff anyway, I think this module is very nice start. Probably you need to grab someone now who has merge permissions to review and merge.

@nlewo
Copy link
Member Author

nlewo commented Dec 11, 2016

@spinus Thanks for your reviews and comments.
If you know one of them, do not hesitate;)
Otherwise, I'll ping them tomorrow on IRC.

@nlewo
Copy link
Member Author

nlewo commented Dec 13, 2016

@domenkozar do you know who could I ping to review and merge this PR? Maybe @FRidh? (sorry for the spam)

policy_file=${cfg.package}/etc/policy.json

[database]
connection = ${cfg.databaseConnection}

connection = "mysql://${cfg.database.user}:${cfg.database.password.pattern}@${cfg.database.host}/${cfg.database.name}"
Copy link
Member

Choose a reason for hiding this comment

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

is hard coding mysql:// wanted here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't test it with another database, so I prefer to let it hardcoded for now. If another backend is required and tested, we could easily add it by preserving backward compatibility.

@@ -0,0 +1,79 @@
{ system ? builtins.currentSystem }:
Copy link
Member

Choose a reason for hiding this comment

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

this test should be referenced in nixos/release.nix, otherwise it won't be automatically run.

Copy link
Member Author

Choose a reason for hiding this comment

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

I pushed a new commit related to your comment... but I'm really not sure it's correct.

Copy link
Member

Choose a reason for hiding this comment

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

do you want set yourself as maintainer for this test, so you get informed in case it fails?

  meta = with pkgs.stdenv.lib.maintainers; {                                                                                                       
    maintainers = [ ...];                                                                                                                             
  }; 

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

A secret can be stored in a file. It is written at runtime in the
configuration file.
Note it is also possible to write them in the nix store for dev
purposes.
@Mic92 Mic92 merged commit 086e5d0 into NixOS:master Dec 16, 2016
@Mic92
Copy link
Member

Mic92 commented Dec 16, 2016

Thanks!

@nlewo
Copy link
Member Author

nlewo commented Dec 16, 2016

@Mic92 @spinus thanks for your reviews!

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.

None yet

4 participants