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

FIPS: replica install check #437

Closed
wants to merge 5 commits into from

Conversation

tkrizek
Copy link
Contributor

@tkrizek tkrizek commented Feb 6, 2017

PR depends on the rest of the FIPS patches.

"Cannot install replica of a server of higher version ({}) than"
"the local version ({})".format(remote_version, api_version))
raise ScriptError(
_("Cannot install replica of a server of higher version "
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't use ugettext in installers, only in plugins

if fips_mode != remote_fips_mode:
if fips_mode:
raise ScriptError(
_("Cannot join FIPS-enabled replica into existing topology: "
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

"FIPS is not enabled on the master server."))
else:
raise ScriptError(
_("Cannot join replica into existing FIPS-enabled topology: "
Copy link
Contributor

Choose a reason for hiding this comment

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

and here

@MartinBasti
Copy link
Contributor

I'm still afraid that users may want to create a FIPS replica from the non-FIPS master, even if it is not recommended due security. How can be this achieved?

@tkrizek
Copy link
Contributor Author

tkrizek commented Feb 6, 2017

@MartinBasti Since this check is performed only during installation, the user could simply install non-FIPS replica and then turn FIPS on afterwards. There might be issues with this approach and thus it is neither recommended nor supported, as stated in the documentation.

@MartinBasti
Copy link
Contributor

@tomaskrizek on current versions of RHEL and fedora IPA doesn't start in FIPS, but upgrading first and then enabling FIPS might be the way

ipalib/config.py Outdated
@@ -44,6 +44,7 @@
from ipalib.constants import CONFIG_SECTION
from ipalib.constants import OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
from ipalib import errors
from ipaplatform.tasks import tasks
Copy link
Contributor

Choose a reason for hiding this comment

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

Importing from ipaplatform to ipalib is forbidden, this will have to be worked around.

raise ScriptError(
"Cannot install replica of a server of higher version "
"(%(remote_version)s) than the local version (%(api_version)s)"
% dict(remote_version=remote_version, api_version=api_version))
Copy link
Contributor

Choose a reason for hiding this comment

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

NACK, .format() is the preferred way of formatting strings.

@@ -1077,7 +1099,7 @@ def promote_check(installer):
remote_api.finalize()
installer._remote_api = remote_api

check_remote_version(remote_api)
check_remote_compatibility(remote_api)
Copy link
Contributor

Choose a reason for hiding this comment

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

This check is executed only in replica promotion. There should be a check for classic replica install as well; IMO it should reject install when FIPS is enabled.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that's what happens now with the is_fips_enabled() guards. Since FIPS is not available on DL0, it should fail.

ipalib/config.py Outdated
@@ -497,6 +498,10 @@ def _bootstrap(self, **overrides):
if 'plugins_on_demand' not in self:
self.plugins_on_demand = (self.context == 'cli')

# Set fips_mode:
if 'fips_mode' not in self:
self.fips_mode = tasks.is_fips_enabled()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want the user to be able to set env.fips_mode during api bootstrapping? I do not think so. This should be set amongst other run-time variables.


# Check FIPS mode compatibility
remote_fips_mode = env['fips_mode']
fips_mode = tasks.is_fips_enabled()
Copy link
Contributor

@stlaz stlaz Feb 7, 2017

Choose a reason for hiding this comment

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

I think you could rather pass use api.env.fips_mode similar to what's done in the api_version.

% dict(remote_version=remote_version, api_version=api_version))

# Check FIPS mode compatibility
remote_fips_mode = env['fips_mode']
Copy link
Contributor

Choose a reason for hiding this comment

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

env does not necessarily contain "fips_mode" key.

@martbab
Copy link
Contributor

martbab commented Feb 7, 2017

@tomaskrizek since you added a new key to the Env object, you will have to fix test_ipalib/test_config.py to account for this change, see https://travis-ci.org/freeipa/freeipa/jobs/198916106#L443

@pvoborni
Copy link
Member

pvoborni commented Feb 7, 2017

@MartinBasti I'm not sure from your comment if you would like to provide a way to change non-FIPS server into a FIPS server or just brainstorming ways how it can be worked around. In any case this path is not a goal and actually should be discouraged. http://www.freeipa.org/page/V4/FreeIPA-on-FIPS#Design

@MartinBasti
Copy link
Contributor

@pvoborni more or less brainstorming, as I'm almost sure that people will want to migrate current deployments to FIPS mode

@tkrizek
Copy link
Contributor Author

tkrizek commented Feb 7, 2017

Thanks for the feedback. Hopefully I addressed all the concerns above in the update.

ipalib/config.py Outdated
@@ -440,6 +444,9 @@ def _bootstrap(self, **overrides):
self.bin = path.dirname(self.script)
self.home = os.environ.get('HOME', None)

if tasks is not None:
self.fips_mode = tasks.is_fips_enabled()
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs an explanation in a comment.

"""
env = client.forward(u'env', u'fips_mode')['result']
remote_fips_mode = env.get('fips_mode', False)
fips_mode = tasks.is_fips_enabled()
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe you left some mess here.

Verify remote server's version is not higher than this server's version

:param client: RPC client

Copy link
Contributor

Choose a reason for hiding this comment

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

Please fill this empty line with the other parameter documentation. Don't leave a blank line before :raises, it's ugly and it's not usually done this way pythonhosted:Sphinx.


:param client: RPC client

:raises: ``ScriptError`` if the checks fails
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be :raises: ScripError: blahblah

@@ -747,6 +786,10 @@ def install_check(installer):
ldap_uri=ldapuri)
remote_api.finalize()
installer._remote_api = remote_api

with rpc_client(remote_api) as client:
check_remote_fips_mode(client, api.env.fips_mode)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you checking fips mode twice in DL1? Also, if this is supposed to address the issue "Explode if trying to install in FIPS on DL0", this won't work.

Copy link
Contributor

Choose a reason for hiding this comment

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

The DL1 twice checking remark is false, thought this code was in common_check(). The other part still applies, though.

@stlaz
Copy link
Contributor

stlaz commented Feb 8, 2017

LGTM

@@ -215,6 +215,7 @@
('script', object), # sys.argv[0]
('bin', object), # The directory containing the script
('home', object), # $HOME
('fips_mode', object), # FIPS-mode of the server
Copy link
Contributor

Choose a reason for hiding this comment

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

Won't this cause api.env.fips_mode to be object rather than unset when ipaplatform is not installed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. I didn't notice these settings are global, not just test-specific. I removed this bit and fixed the test instead.

if remote_version > api_version:
raise RuntimeError(
if remote_version > local_version:
raise ScriptError(
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that ScriptError is really only necessary when you need the script to fail with a specific exit code. If you don't need that and are fine with exit code 1, RuntimeError is all you need.

@@ -563,7 +563,7 @@ def test_finalize_core(self):
# Test using DEFAULT_CONFIG:
defaults = dict(constants.DEFAULT_CONFIG)
(o, home) = self.finalize_core(None, **defaults)
assert list(o) == sorted(defaults)
assert set(o).issuperset(set(defaults))
Copy link
Contributor

Choose a reason for hiding this comment

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

I would rather keep the original check, but make sure that o does not contain fips_mode before doing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure how you'd like to make sure o doesn't contain fips_mode. Env object does not allow deletion and the only way I can think of would be to violate the object's "private" properties.

I propose we either:

  • always set fips_mode: to True, False or None
  • accept that Env can now have optional attributes and use the test proposed above

Copy link
Contributor

Choose a reason for hiding this comment

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

You can just add the fips_mode into ipalib/constants and set its value to object. We had to do this workaround when @tiran added nss_dir to the config (see https://github.com/freeipa/freeipa/blob/master/ipalib/constants.py#L228). The test in the original from will then just work(R).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@martbab I tried to do that, but that also sets the fips_mode key for the env object, doesn't it? We want the fips_mode key to not be present if ipaplatform wasn't imported.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should work:

    defaults = dict(constants.DEFAULT_CONFIG)
    defaults['fips_mode'] = None
    (o, home) = self.finalize_core(None, **defaults)
    assert list(o) == sorted(defaults)

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, of course! fixed

@tkrizek tkrizek force-pushed the t5695-fips-install-check branch 3 times, most recently from 3c816db to af915d1 Compare February 15, 2017 14:55
@tkrizek tkrizek force-pushed the t5695-fips-install-check branch 2 times, most recently from 144bbed to 28c57e4 Compare February 15, 2017 15:53
@@ -738,6 +775,7 @@ def install_check(installer):
ldap_uri=ldapuri)
remote_api.finalize()
installer._remote_api = remote_api

Copy link
Contributor

Choose a reason for hiding this comment

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

Why was the "FIPS is not allowed in domain level 0" check removed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -562,6 +562,7 @@ def test_finalize_core(self):

# Test using DEFAULT_CONFIG:
defaults = dict(constants.DEFAULT_CONFIG)
defaults['fips_mode'] = object
Copy link
Contributor

Choose a reason for hiding this comment

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

object. Huh?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, to skip the value check (few lines below - https://github.com/freeipa/freeipa/pull/437/files/28c57e48423e77756eb152068db44933cd0540f7#diff-c5fcc8900faeb561ad5f2a58fef94c85L568 ). If we set it to None, the test will check whether fips_mode value is None - which is not the desired behavior.

@HonzaCholasta
Copy link
Contributor

LGTM.

@stlaz
Copy link
Contributor

stlaz commented Feb 21, 2017

3 LGTM + tests passing seems like a good enough reason for ACK to me.

@stlaz stlaz added the ack Pull Request approved, can be merged label Feb 21, 2017
@MartinBasti
Copy link
Contributor

Needs rebase

Tomas Krizek added 5 commits February 21, 2017 16:48
Variable fips_mode indicating whether machine is running in
FIPS-enabled mode was added to env.

https://fedorahosted.org/freeipa/ticket/5695
Refactor function to use ScriptError exception and provide docstring.
Abstract creating rpc client into a context manager to allow re-use.
Check status of remote server's FIPS mode and proceed with
installation only if it matches the current replica's FIPS mode.

https://fedorahosted.org/freeipa/ticket/5695
@MartinBasti MartinBasti added the pushed Pull Request has already been pushed label Feb 21, 2017
@tkrizek tkrizek deleted the t5695-fips-install-check branch September 15, 2017 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ack Pull Request approved, can be merged pushed Pull Request has already been pushed
Projects
None yet
6 participants