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
Allow full customisability of IPA CA subject DN #245
Allow full customisability of IPA CA subject DN #245
Conversation
| .TP | ||
| \fB\-\-subject\-base\fR=\fISUBJECT\fR | ||
| The subject base for certificates issued by IPA (default O=REALM.NAME) | ||
| .TP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment that the order of RDNs is in LDAP order, not in X.509 order. It might cause some confusing. Users (like me) expect the order of RDNs like in OpenSSL or Firefox.
| The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME) | ||
| .TP | ||
| \fB\-\-subject\-base\fR=\fISUBJECT\fR | ||
| The subject base for certificates issued by IPA (default O=REALM.NAME) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dito
| 'givenname', 'initials', 'generationqualifier', 'dc', 'mail', 'uid', | ||
| 'postaladdress', 'postalcode', 'postofficebox', 'houseidentifier', 'e', | ||
| 'street', 'pseudonym', 'incorporationlocality', 'incorporationstate', | ||
| 'incorporationcountry', 'businesscategory', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenSSL has slightly different short names (email instead of e).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's an issue. I didn't change any of them, anyhow - so if it is a problem we can address in another ticket / commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should mention the RDNs in the man page. After all OpenSSL is a de-facto standard.
fc7cddf
to
e3419a4
Compare
|
Added a new commit to add DNs-in-ldap-order comments. |
|
flake8 violation: |
|
@tiran I haven't a clue about that pep8 error... my commits don't even touch that file. |
|
@frasertweedale I don't have a clue, either. Let's ignore the message. |
| default=None, | ||
| help=( | ||
| "The certificate subject base " | ||
| "(default O=<realm-name>)")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this deservers a separate "add missing --subject-base to ipa-ca-install" commit, because the option should have been there since ipa-ca-install gained the ability to install CA master.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you wish. PR updated.
e3419a4
to
5c0f866
Compare
5c0f866
to
382bbff
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides inline comments:
--subject-baseand--ca-subjectshould be forbidden inipa-server-installin CA-less mode.--subject-baseand--ca-subjectshould be forbidden inipa-ca-installwhen installing a CA replica.- The
ServerReplicaInstallclass needs an update (renamesubjecttosubject_base, addca_subject = None). - We should stop updating
ipaCertificateSubjectBaseandcertmap.confin CA-less mode (perhaps in other PR).
| 0, | ||
| re.MULTILINE) | ||
| with open(certmap_filename, 'w') as f: | ||
| f.write(certmap_conf) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please re-use DSInstance.__certmap_conf(). We don't need any more duplicate-but-not-quite-copy-paste code in installers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, no worries cobber.
| set_subject_base_in_config(realm, dm_password, subject_base) | ||
|
|
||
| # sysupgrade | ||
| sysupgrade.set_upgrade_state('certmap.conf', 'subject_base', subject_base) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would really like if we stopped putting subject base in sysupgrade and update DSInstance.find_subject_base(), which is the only user of it, to always read subject base from LDAP.
You are already touching find_subject_base(), so I'm assuming this change would be OK in this PR as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wary of the greater scope of that change (hence I filed a separate ticket for it).
I really had no choice but to remove the certmap.conf lookup from find_subject_base() for this ticket though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the scope is not big (only 4 places including this one need an update), but OK.
| ipa_ca_nickname = get_ca_nickname(config.realm_name) | ||
| db = certs.CertDB(config.realm_name, nssdir=paths.IPA_NSSDB_DIR) | ||
| cert = db.get_cert_from_db(ipa_ca_nickname) | ||
| options.ca_subject = six.text_type(DN(x509.load_certificate(cert).subject)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a duplicate of code in ca.install_check(). I believe this should in fact be done only in ca.install_check().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it was done here to calculate ca_subject for reset_subject_config(). Per your other review comment, this will be moved to ca.install() so this code can go away.
| api.env.realm, | ||
| options.subject_base, | ||
| ) | ||
| reset_subject_config(api.env.realm, options.ca_subject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be done from inside ca.install(). The ultimate goal for ipa-ca-install is to be just a thin wrapper around ipaserver.install.ca, so the code will end up there sooner or later. I would prefer sooner ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
| ipa_ca_nickname = certdb.get_ca_nickname(realm_name) | ||
| db = certs.CertDB(realm_name, nssdir=paths.IPA_NSSDB_DIR) | ||
| cert = db.get_cert_from_db(ipa_ca_nickname) | ||
| return unicode(DN(x509.load_certificate(cert).subject)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not rely on information from the local filesystem in new code. You should use LDAP whenever possible, because unlike the local filesystem, it is guaranteed to have up-to-date information. Here you can use (off the top of my head):
try:
ca_subject = api.Command.ca_show(u'ipa')['result']['ipacasubjectdn']
except errors.CommandError:
ca_subject = installutils.default_ca_subject_dn(config.subject_base)
return unicode(ca_subject)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this gets looked up during install_check, before replica DS is created, so we would have to use a remote_api. Now, what if the master is pre freeipa-4.2 thus lacks the ca plugin?
I don't think your suggested approach works in this case. Shall we stay with reading the CA subject DN from the IPA CA cert, or do you have another suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using remote_api here should be OK. If the master does not have ca_show, the default CA subject should be used (hence the try-except in the snippet).
| @@ -330,7 +330,8 @@ def configure_instance(self, host_name, dm_password, admin_password, | |||
| pkcs12_info=None, master_host=None, csr_file=None, | |||
| cert_file=None, cert_chain_file=None, | |||
| master_replication_port=None, | |||
| subject_base=None, ca_signing_algorithm=None, | |||
| subject_base=None, subject=None, | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subject should actually be named ca_subject I guess. Ditto for self.subject and DSInstance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
| certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) | ||
| certdb = certs.CertDB( | ||
| self.realm, nssdir=dirname, | ||
| subject_base=self.subject_base, ca_subject=self.subject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nitpick: IMO a list of arguments is much easier on the eyes than a matrix / block of arguments:
# good
certdb = certs.CertDB(self.realm,
nssdir=dirname,
subject_base=self.subject_base,
ca_subject=self.subject)
# also good
certdb = certs.CertDB(
self.realm,
nssdir=dirname,
subject_base=self.subject_base,
ca_subject=self.subject)
# not so good
certdb = certs.CertDB(
self.realm, nssdir=dirname,
subject_base=self.subject_base, ca_subject=self.subject)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. (Disagree with first approach though; what if we rename var certdb, module certs or class CertDB and length changes? You don't want to realign N extra lines for all the arguments :)
| @@ -704,6 +709,10 @@ def install_check(installer): | |||
| raise RuntimeError("CA cert file is not available. Please run " | |||
| "ipa-replica-prepare to create a new replica file.") | |||
|
|
|||
| # look up CA subject name (needed for DS certmap.conf) | |||
| options.subject = unicode( | |||
| DN(x509.load_certificate_from_file(cafile).subject)) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you meant options.ca_subject.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes; thanks.
| if 'ipacertificatesubjectbase' not in entry_attrs: | ||
| cur_subject_base = entry_attrs.get('ipacertificatesubjectbase', [None]) | ||
| if not cur_subject_base[0] \ | ||
| or DN(cur_subject_base[0]) != DN(subject_base): | ||
| entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] | ||
| conn.update_entry(entry_attrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an exception handling-based approach might be better:
entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)]
try:
conn.update_entry(entry_attrs)
except errors.EmptyModlist:
passThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is nicer; will do.
| subject_base = options.subject_base | ||
| else: | ||
| ca_subject = lookup_ca_subject(options.realm_name) | ||
| subject_base = replica_config.subject_base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than duplicating this below in install_step_0() and install_step_1(), it would be better to store the values in options._ca_subject and options._subject_base and reuse them in install_step_0() and install_step_1().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that works fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, actually this does not work fine :(
I cannot set the knob value directly because, in the replica_install case, the ca_subject and subject_base knobs have been replaced by a removed property. (ipalib/install/service.py:51).
I cannot set options._ca_subject (or ._subject_base) and then read it back later because the options.__getattr__ raises AttributeError if the attr name does not correspond to a knob name (ipapython/install/core.py:571).
I find the installer/knob code quite hard to follow... do you have a suggestion? (I certainly agree with your original point that it is preferable to compute the values once only, and cache them).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Previous comment is incorrect; please disregard)
|
@jcholast: new tickets pertaining to subject_base / certmap.conf config:
Other review comments will be addressed in due course. Thanks for reviewing. |
606cb7f
to
42a3091
Compare
|
Refactor set_subject_base_in_config to use api.Backend.ldap2 instead of a manually created LDAP connection. Also rename the function to have a more accurate name, and move it to 'ipaserver.install.ca' to avoid cyclic import (we will eventually need to use it from within that module). Part of: https://fedorahosted.org/freeipa/ticket/2614
`installutils.load_external_cert` assumes that the IPA CA subject
DN is `CN=Certificate Authority, {subject_base}`. In preparation
for full customisability of IPA CA subject DN, push this assumption
out of this function to call sites (which will be updated in a
subsequent commit).
Part of: https://fedorahosted.org/freeipa/ticket/2614
The --subject option is actually used to provide the "subject base". We are also going to add an option for fully specifying the IPA CA subject DN in a subsequent commit. So to avoid confusion, rename --subject to --subject-base, retaining --subject as a deprecated alias. Part of: https://fedorahosted.org/freeipa/ticket/2614
For full customisability of the IPA CA subject DN, we will need the ability to update DS `certmap.conf' when upgrading a deployment from CA-less to CA-ful. Extract the existing behaviour, which is private to DsInstance, to the `write_certmap_conf' top-level function. Also update `certmap.conf.template' for substition of the whole CA subject DN (not just the subject base). Part of: https://fedorahosted.org/freeipa/ticket/2614
The ca_enabled_check function is a wrapper around api.Command.ca_is_enabled. When using remote_api (e.g. during installer), ca_enabled_check invokes the *global* api instead of the remote_api. Update ca_enabled_check to explicitly receive an api object from the caller and invoke Command.ca_is_enabled through it. Part of: https://fedorahosted.org/freeipa/ticket/2614
Currently only the "subject base" of the IPA CA subject DN can be customised, via the installer's --subject-base option. The RDN "CN=Certificate Authority" is appended to form the subject DN, and this composition is widely assumed. Some administrators need more control over the CA subject DN, especially to satisfy expectations of external CAs when the IPA CA is to be externally signed. This patch adds full customisability of the CA subject DN. Specifically: - Add the --ca-subject option for specifying the full IPA CA subject DN. Defaults to "CN=Certificate Authority, O=$SUBJECT_BASE". - ipa-ca-install, when installing a CA in a previous CA-less topology, updates DS certmap.conf with the new new CA subject DN. - DsInstance.find_subject_base no longer looks in certmap.conf, because the CA subject DN can be unrelated to the subject base. Fixes: https://fedorahosted.org/freeipa/ticket/2614
Update man pages and help output to indicate that --subject-base and --ca-subject options interpret their arguments in LDAP order. Fixes: https://fedorahosted.org/freeipa/ticket/6455
42a3091
to
4f98a26
Compare
|
@HonzaCholasta PR updated. Re ticket URL, I think 2614 is the correct one for that commit. |
|
@frasertweedale, the ticket number is correct, but the URL points to Dogtag Trac. |
Print an error and terminate if --ca-subject or --subject-base are used when installing a CA-less master or when performing standalone installation of a CA replica. Part of: https://fedorahosted.org/freeipa/ticket/2614
|
@HonzaCholasta whups! Thanks for clarifying; fixed. |
4f98a26
to
d280924
Compare
This patchset adds full customisability of CA subject DN apart from
subject base, via the ipa-server-install
--ca-subjectoption. Italso renames ipa-server-install
--subjectoption to--subject-base, and adds--ca-subjectand--subject-baseoptions to ipa-ca-install.
Earlier version of this patchset was previously reviewed by
@jcholast on freeipa-devel:
https://www.redhat.com/archives/freeipa-devel/2016-August/msg00570.html
All review items have been addressed, except for item 9. The
suggestion will not work because a fair bit of code besides
what's in
ipaserver.install.carequires knowing the CA Subject DNand/or subject base. So the defaults must be applied close to the
"entry points".
I also carved a few smaller commits out of the main patch (but it is
still pretty big and hairy to review).
https://fedorahosted.org/freeipa/ticket/2614