Tag Archives: Security

ID range management in IPA

POSIX IDs and IPA

Local domain range

IPA is an identity management solution that allows to centrally define users and groups. As it operates in Linux environments, the users and groups are defined with a name and a POSIX ID (a numeric value), that are used for access control: each file belongs to a user and a group identified by their POSIX ID, sudo rules evaluation relies on POSIX IDs and so on.

When users and groups are created inside IPA, they can either be created with a provided id or the admin can let IPA assign an id. The range from which the ids can be picked is defined at the IPA level and is represented by a local ID range visible with the ipa idrange-find command:

[root@server ~]# ipa idrange-find
---------------
1 range matched
---------------
  Range name: IPA.TEST_id_range
  First Posix ID of the range: 936000000
  Number of IDs in the range: 200000
  Range type: local domain range
----------------------------
Number of entries returned 1
----------------------------

During the first IPA server installation, this ID range can either be provided through a base ID number (—idstart) and a max ID (—id max), or be picked randomly by the installer.

In the above example, the users and groups will get assigned IDs starting from 936000000, up to 936000000 + 200000 (not included).

When the ID range is depleted, the admin can extend the possible ID numbers by defining additional local ranges (ipa idrange-add --type ipa-local).

Other types of ranges

When IPA has configured a trust with an Active Directory forest, the users and groups defined in AD also need to have a POSIX ID for access control performed on IPA side. There are 2 different situations:

  • if AD has been extended with Identity Management for UNIX, and is also storing a uidNumber and a gidNumber for each user, and a gidNumber for each group, then IPA can directly re-use the POSIX IDs stored on AD side. The trust is established with a range type “Active Directory domain with POSIX attributes” (ipa-ad-trust-posix).
  • If AD doesn’t store POSIX IDs, IPA maps the unique SID value from AD users and groups to a POSIX ID based on settings defined for the trust. The trust is established with a range type “Active Directory domain” (ipa-ad-trust) and sets the first POSIX ID for the mapping.

As a summary, IPA manages 3 different types of ID ranges:

  • local domain
  • active directory domain
  • active directory domain with POSIX attributes

In any case, the various ranges must not overlap in order to guarantee that an ID corresponds to a unique user or group.

Next available ID

DNA range plugin

During the first server installation, the local ID range is set and defines the range from which IDs get picked for new IPA users and groups. This local ID range is used for the whole IPA deployment.

The server is then configured with the DNA range plugin (Dynamic Number Assignment), that provides a mechanism to automatically assign IDs but also ensure existing IDs are not re-used. The implementation is simple to understand: the DNA plugin stores the next available ID and assigns the IDs sequentially.

The existing DNA ranges can be seen using ipa-replica-manage dnarange-show. If the command is run when there is a single server, the output looks like the following:

[root@server ~]# ipa-replica-manage  dnarange-show
server.ipa.test: 936000000-936199999

The DNA range on the first server starts from the same value as the local domain ID range , and ends on first POSIX ID + number of IDs – 1. When the first user gets created, he is assigned a POSIX ID, and the DNA range plugin increments the next available value:

[root@server ~]# ipa user-add idmuser1 --first idm --last user1 
...
[root@server ~]# ipa-replica-manage  dnarange-show
server.ipa.test: 936000002-936199999

The above output shows that the available range has shrinked due to the new user taking one ID. Note that the first ID (936000000) is reserved for the admin user.

Splitting ranges between replicas

When additional servers (replicas) are set up, it is important to make sure that a given ID is not assigned at the same time by 2 different replicas to different users/groups. In order to avoid this type of conflict, each replica is also configured with the DNA range plugin (dynamic number assignment).

[root@server ~]# ipa-replica-manage  dnarange-show
server.ipa.test: 936000002-936199999
replica.ipa.test: No range set

The above command shows that the replica hasn’t created yet any user or group and didn’t request any DNA range. But as soon as the replica needs to assign an ID, it communicates with the server and grabs a sub-range:

[root@replica ~]# ipa user-add idmuser2 --first idm --last user2
...
[root@replica ~]# ipa-replica-manage dnarange-show
server.ipa.test: 936000002-936100499
replica.ipa.test: 936100501-936199999

The output shows that server.ipa.test abandoned part of its range to replica.ipa.test. From now on, server.ipa.test will be able to assign IDs up to 936100499, while replica.ipa.test will assign IDs starting from 936100501 (he assigned 936100500 to the new user).

The DNA range is configured locally to each replica, in a part of the configuration that is not replicated. The DNA range records the next available ID and the max available ID. Remember, the DNA range is constantly evolving: as soon as a replica assigns an ID to a new user, the next available ID is incremented and the range shrinks over time.

It is important to make sure that DNA ranges are not overlapping, and that each DNA range fits into local ID ranges.

Frequent issues

Issues can happen when a replica doesn’t have any assigned DNA range and fails to grab a range when it needs to (for instance because the only other server he knows is down).

In this case, manual remediation is possible using ldapmodify, by editing the DNA range plugin configuration on the replica. The DNA range plugin configuration can be seen within the following LDAP entry:

[root@replica ~]# ldapsearch -LLL -D "cn=directory manager" -W -o ldif-wrap=no -b "cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config" dnaMaxValue dnaNextValue 
Enter LDAP Password: 
dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
dnaMaxValue: 936199999
dnaNextValue: 936100501

Note that the DNA range plugin has different values on each replica, and the ranges must not overlap and must not include already assigned IDs.

Another type of issue arises when the ID ranges are depleted. In this case, a new local id range can be added with a new range of values.

The official documentation contains a whole chapter related to Adjusting ID ranges manually and is a recommended read. I would also like to point to Rob’s blog “FreeIPA and no DNA range” for more details.

Advertisement

Demystifying the Certificate Authority component in FreeIPA

When I joined the FreeIPA team, I wanted to start by getting more familiar with the product from a user perspective and the first step was to install FreeIPA server.

I opened the Linux Domain Identity, Authentication, and Policy Guide, tried to figure out which options would be useful and… I froze when I reached the section Determining which CA configuration to use. I had literally no idea what the documentation meant by “Server with an integrated IdM CA” or “Server without a CA“. But I had to choose something to start with.
In this blog post, I will explain what this choice really means, and what are the consequences of picking one over the other.

Basic requirement: HTTP and LDAP server certificates

First of all, FreeIPA is composed of many services accessed through the network, among which a LDAP server and an HTTP server. These 2 services can be accessed through a standard port (in clear) or through a SSL port, meaning that they both need a server certificate.

The HTTP and LDAP server certificates are needed during the installation, because the installer will put them in the right NSS database and configure their nickname and location for the HTTP and LDAP servers to find them. There are multiple ways to obtain server certificates, but one needs to understand first the basic notions around Public Key Infrastructure (PKI).

I will use a comparison with the delivery of a passport: in order to have a passport issued with your name, you need to provide official documents (for instance a birth certificate and a photo) to the government agency that will validate the documents, make sure that you are who you claim to be, and then issue the passport. The server certificate can be compared to the passport, that will later prove your identity to whoever trusts the government agency, and the government agency can be compared to the Certificate Authority.

So in order to obtain server certificates, it is possible to:

  • request certificates to an official Certificate Authority. Many commercial or non-profit companies provide this type of service (Verisign, Let’sEncrypt, GoDaddy etc…)
  • request certificates to a home-made Certificate Authority. It is possible to create a home-made self-signed Certificate Authority with tools such as certutil or openssl. The main difference with the previous method is that people are less likely to trust your home-made CA (it’s like asking them to accept a passport that was issued by a newly founded country not recognized yet by the rest of the world). Self-signed here means that the Certificate Authority passport  is delivered by… the Certificate Authority itself!
  • install your own Certificate Authority with FreeIPA, that will sign the certificates needed by the HTTP and LDAP server.

The last option corresponds to a “Server with an integrated IdM CA” and has many advantages over the first options:

  • certificates have a limited lifetime and need to be renewed before they expire (otherwise the HTTP/LDAP servers stop working). The renewal process is time-consuming but also can be forgotten if the sysadmin does not carefully track the dates, leaving the deployment in a state where some services become unavailable.
    When FreeIPA is installed with an embedded Certificate Authority, FreeIPA automatically monitors the expiry dates of the certificates and triggers a renewal a few weeks before expiration, ensuring service continuity. This is the first advantage of the embedded CA, but not the only one.
  • FreeIPA with an embedded CA is also able to deliver certificates for the users, the hosts or the services managed by FreeIPA. Various certificates profiles can be defined, populating specific fields in each type of certificate (for instance extensions with the OCSP responder URL…)
    For more information on the embedded Certificate Authority, you can refer to Dogtag Certificate System documentation (the embedded CA in FreeIPA is a tailored version of Dogtag).

At this point, if you decide to install FreeIPA with an embedded Certificate Authority, there are 2 possible choices. The embedded CA can either be:

  • a self-signed CA: the Certificate Authority is created “from scratch” without the need for any external authority. It is the root CA, meaning that its own certificate was not delivered by anyone else but signed by itself.
  • a CA subordinate to an external CA. This means that FreeIPA CA certificate was signed by another CA, a sort of parent CA.

 

Corresponding installation options

CA-less installation

As said above, we need one certificate for the HTTP server and one for the LDAP server.  They have to be provided to ipa-server-install or ipa-replica-install with the options:

  • –http-cert-file / –http-pin: file containing the HTTP server certificate + private key and password protecting the file
  • –dirsrv-cert-file / –dirsrv-pin: file containing the LDAP server certificate + private key and password protecting the file

Installation with an embedded self-signed CA

FreeIPA CA is created during FreeIPA installation, and generates the HTTP and LDAP certificates. There is no need to provide any cert file! No options!

Installation with an externally-signed embedded CA

The installation is a 2-step process. In the first step, ipa-server-install must be called with –external-ca and generates a CSR file (Certificate Signing Request). This CSR file needs to be sent to the external CA that will perform a bunch of validations to authenticate the recipient of the certificate and issue a certificate for FreeIPA Certificate Authority.

In the second step, ipa-server-install is called with –external-cert-file to provide the certificate obtained from the external CA. The installer then configures FreeIPA certificate authority as a subCA of the external CA, and FreeIPA CA can issue the HTTP and LDAP server certificates.

 

What if…

I installed FreeIPA without any embedded CA but I change my mind?

FreeIPA allows to install an embedded CA at a later time, using ipa-ca-install. The tool provides the same options as ipa-server-install: you can either install a self-signed CA or an externally signed CA.

Important: installing an embedded CA with ipa-ca-install does not replace the HTTP and LDAP server certificates. If they were initially delivered by an external CA, they will not be automatically renewed.

I installed FreeIPA with a self-signed CA but I’d rather have an externally-signed CA?

FreeIPA allows to switch from self-signed CA to externally-signed CA using ipa-cacert-manage renew –external-ca. This is a 2-step process similar to ipa-server-install –external-ca, where the 1st step produces a CSR that needs to be supplied to an external CA. The external CA then issues a CA cert that is provided back to ipa-cacert-manage renew through the –external-cert-file option.

I installed FreeIPA with an externally signed CA but I’d rather have a self-signed CA?

FreeIPA allows to switch from externally signed CA to self-signed CA using ipa-cacert-manage renew –self-signed.

I want to replace HTTP and LDAP certificates with certificates signed by a third-party Certificate Authority?

FreeIPA provides the ipa-server-certinstall tool that will replace the current HTTP or LDAP certificates with the certs provided in the file.
Important: ipa-server-certinstall can be called to install externally signed certificates for HTTP and LDAP even if FreeIPA is installed with an embedded CA. In this case, FreeIPA CA still has the capability to issue certificates for users, hosts or services. The only difference is that HTTP and LDAP certificates are not issued by IPA CA.

 

Other FreeIPA commands related to certificates

When an embedded CA is installed, its certificate must be present in various files or NSS databases on all the FreeIPA hosts (master, replicas and clients) so that any FreeIPA machine trusts the certificates delivered by the embedded CA.

In addition to that, the HTTP and LDAP server certificates can be issued either by IPA CA or by an external CA, and the issuer can even be changed over time. In the external CA case, this means that the external CA needs to be trusted by all the FreeIPA machines for the IPA commands to work (the CLI communicates with the HTTP server using the https port, and this requires to trust the CA that issued the HTTP server certificate). Yet another CA certificate to add to files and databases on all the FreeIPA machines…

To ease this configuration, the tool ipa-certupdate is able to retrieve the CA certificates stored in LDAP (the embedded FreeIPA CA or the external CA certs), and install them in all the relevant files and NSS databases. It needs to be called when the CA cert is manually renewed or when a new external CA cert is added.

ipa-cacert-manage install is used to add a new external CA certificate in the LDAP store. It does not replace FreeIPA embedded CA but rather declares another certificate authority as trusted. This is useful when the HTTP and LDAP server certificates need to be replaced by certs signed by a new CA, not yet known by FreeIPA. After calling ipa-cacert-manage install (that puts the new CA in LDAP store), you need to call ipa-certupdate on all FreeIPA machines (to get the CA from the LDAP store and put it in the local NSS databases).

ipa cert-request is used to request new certificates for users, hosts or services. The certificate is signed by FreeIPA embedded CA (meaning that this command is available only when an embedded CA is configured).

Conclusion

By now you should be able to pick a deployment option and understand the differences between CA-less or with embedded CA, and self-signed CA or externally-signed CA.

You should also be aware that your choice is not definitive and that it is possible to install a CA at a later time or change your certificate chain from self-signed to externally-signed and vice-versa.

Troubleshooting FreeIPA: pki-tomcatd fails to start

When performing the upgrade of FreeIPA, you may encounter an issue with pki-tomcatd failing to start. At first this issue looks related to the upgrade, but often reveals a latent problem and gets detected only because the upgrade triggers a restart of pki-tomcatd.

So how to troubleshoot this type of issue?

 

Upgrade logs

The upgrade is using /var/log/ipaupgrade.log and may contain a lot of useful information. In this specific case, I could see:

[...] DEBUG The ipa-server-upgrade command failed,
exception: ScriptError: CA did not start in 300.0s
[...] ERROR CA did not start in 300.0s
[...] ERROR The ipa-server-upgrade command failed. See
/var/log/ipaupgrade.log for more information

 

CA debug logs

The first step is to understand why pki-tomcatd refuses to start. This process is launched inside Tomcat and corresponds to the CA component of FreeIPA. It is logging into /var/log/pki/pki-tomcat/ca/debug:

[...][localhost-startStop-2]: ============================================
[...][localhost-startStop-2]: ===== DEBUG SUBSYSTEM INITIALIZED =======
[...][localhost-startStop-2]: ============================================
[...][localhost-startStop-2]: CMSEngine: restart at autoShutdown? false
[...][localhost-startStop-2]: CMSEngine: autoShutdown crumb file path? /var/lib/pki/pki-tomcat/logs/autoShutdown.crumb
[...][localhost-startStop-2]: CMSEngine: about to look for cert for auto-shutdown support:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: found cert:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: done init id=debug
[...][localhost-startStop-2]: CMSEngine: initialized debug
[...][localhost-startStop-2]: CMSEngine: initSubsystem id=log
[...][localhost-startStop-2]: CMSEngine: ready to init id=log
[...][localhost-startStop-2]: Creating RollingLogFile(/var/lib/pki/pki-tomcat/logs/ca/signedAudit/ca_audit)
[...][localhost-startStop-2]: Creating RollingLogFile(/var/lib/pki/pki-tomcat/logs/ca/system)
[...][localhost-startStop-2]: Creating RollingLogFile(/var/lib/pki/pki-tomcat/logs/ca/transactions)
[...][localhost-startStop-2]: CMSEngine: restart at autoShutdown? false
[...][localhost-startStop-2]: CMSEngine: autoShutdown crumb file path? /var/lib/pki/pki-tomcat/logs/autoShutdown.crumb
[...][localhost-startStop-2]: CMSEngine: about to look for cert for auto-shutdown support:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: found cert:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: done init id=log
[...][localhost-startStop-2]: CMSEngine: initialized log
[...][localhost-startStop-2]: CMSEngine: initSubsystem id=jss
[...][localhost-startStop-2]: CMSEngine: ready to init id=jss
[...][localhost-startStop-2]: CMSEngine: restart at autoShutdown? false
[...][localhost-startStop-2]: CMSEngine: autoShutdown crumb file path? /var/lib/pki/pki-tomcat/logs/autoShutdown.crumb
[...][localhost-startStop-2]: CMSEngine: about to look for cert for auto-shutdown support:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: found cert:auditSigningCert cert-pki-ca
[...][localhost-startStop-2]: CMSEngine: done init id=jss
[...][localhost-startStop-2]: CMSEngine: initialized jss
[...][localhost-startStop-2]: CMSEngine: initSubsystem id=dbs
[...][localhost-startStop-2]: CMSEngine: ready to init id=dbs
[...][localhost-startStop-2]: DBSubsystem: init() mEnableSerialMgmt=true
[...][localhost-startStop-2]: Creating LdapBoundConnFactor(DBSubsystem)
[...][localhost-startStop-2]: LdapBoundConnFactory: init
[...][localhost-startStop-2]: LdapBoundConnFactory:doCloning true
[...][localhost-startStop-2]: LdapAuthInfo: init()
[...][localhost-startStop-2]: LdapAuthInfo: init begins
[...][localhost-startStop-2]: LdapAuthInfo: init ends
[...][localhost-startStop-2]: init: before makeConnection errorIfDown is true
[...][localhost-startStop-2]: makeConnection: errorIfDown true
[...][localhost-startStop-2]: TCP Keep-Alive: true
[...][localhost-startStop-2]: SSLClientCertificateSelectionCB: Setting desired cert nickname to: subsystemCert cert-pki-ca
[...][localhost-startStop-2]: LdapJssSSLSocket: set client auth cert nickname subsystemCert cert-pki-ca
[...][localhost-startStop-2]: SSL handshake happened
Could not connect to LDAP server host ipaserver.ipadomain.com port 636 Error netscape.ldap.LDAPException: Authentication failed (49)
 at com.netscape.cmscore.ldapconn.LdapBoundConnFactory.makeConnection(LdapBoundConnFactory.java:205)
 at com.netscape.cmscore.ldapconn.LdapBoundConnFactory.init(LdapBoundConnFactory.java:166)
 at com.netscape.cmscore.ldapconn.LdapBoundConnFactory.init(LdapBoundConnFactory.java:130)
 at com.netscape.cmscore.dbs.DBSubsystem.init(DBSubsystem.java:654)
 at com.netscape.cmscore.apps.CMSEngine.initSubsystem(CMSEngine.java:1172)
 at com.netscape.cmscore.apps.CMSEngine.initSubsystems(CMSEngine.java:1078)
 at com.netscape.cmscore.apps.CMSEngine.init(CMSEngine.java:570)
 at com.netscape.certsrv.apps.CMS.init(CMS.java:188)
 at com.netscape.certsrv.apps.CMS.start(CMS.java:1621)
 at com.netscape.cms.servlet.base.CMSStartServlet.init(CMSStartServlet.java:114)
 at javax.servlet.GenericServlet.init(GenericServlet.java:158)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:288)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:285)
 at java.security.AccessController.doPrivileged(Native Method)
 at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
 at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:320)
 at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:175)
 at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:124)
 at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1270)
 at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1195)
 at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1085)
 at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5318)
 at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5610)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
 at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
 at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:133)
 at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:156)

The exception shows that LDAP authentication failed with return code 49: invalid credentials.

 

Communication between pki-tomcatd and the LDAP server

We can see that pki-tomcatd is trying to open a LDAP connection through SSL but fails to authenticate. Within FreeIPA, pki-tomcat is storing data in the 389-ds LDAP server and needs to communicate through LDAP with this server.

The configuration of this communication channel can be read in /etc/pki/pki-tomcat/ca/CS.cfg:

internaldb.ldapauth.authtype=SslClientAuth
internaldb.ldapauth.bindDN=cn=Directory Manager
internaldb.ldapauth.bindPWPrompt=internaldb
internaldb.ldapauth.clientCertNickname=subsystemCert cert-pki-ca
internaldb.ldapconn.host=ipaserver.ipadomain.com
internaldb.ldapconn.port=636
internaldb.ldapconn.secureConn

The connection is using port 636 (SSL port) with SSL Client authentication (authtype=SslClientAuth). This means that pki-tomcatd provides a user certificate to the LDAP server, and the LDAP server maps a user to this certificate in order to authenticate the communications.

Note: Authtype can either be SslClientAuth or BasicAuth (authentication with username and password).

In this case, the SSL client authentication is done with the certificate named ‘subsystemCert cert-pki-ca‘ that is stored in /etc/pki/pki-tomcat/alias. So what could be causing the authentication to fail? We need to check that the certificate is available in /etc/pki/pki-tomcat/alias and that pki-tomcat is able to use the associated private key, and that the LDAP server is able to map this certificate to a user.

 

Check the subsystemCert cert-pki-ca

The first step consists in making sure that this certificate is present in /etc/pki/pki-tomcat/alias:

$ sudo certutil -L -d /etc/pki/pki-tomcat/alias -n 'subsystemCert cert-pki-ca'
Certificate:
 Data:
 Version: 3 (0x2)
...

 

Then make sure that the private key can be read using the password found in /var/lib/pki/pki-tomcat/conf/password.conf (with the tag internal=…)

$ sudo grep internal /var/lib/pki/pki-tomcat/conf/password.conf | cut -d= -f2 > /tmp/pwdfile.txt
$ sudo certutil -K -d /etc/pki/pki-tomcat/alias -f /tmp/pwdfile.txt -n 'subsystemCert cert-pki-ca'
certutil: Checking token "NSS Certificate DB" in slot "NSS User Private Key and Certificate Services"
< 0> rsa 86a7fe00cc2a01ad085f35d4ed3e84e7b82ab4f5 subsystemCert cert-pki-ca

At this point we know that pki-tomcat is able to access the certificate and the private key. So the issue is likely to be on the LDAP server side.

Note: depending on your version, the nickname of the certificate may also be prefixed with ‘NSS Certificate DB:’. In this case, run the following command:

$ sudo certutil -K -d /etc/pki/pki-tomcat/alias -f /tmp/pwdfile.txt -n 'NSS Certificate DB: subsystemCert cert-pki-ca'

 

LDAP server configuration

The LDAP configuration describes how a certificate can be mapped to a user in /etc/dirsrv/slapd-IPADOMAIN-COM/certmap.conf:

$ sudo cat /etc/dirsrv/slapd-IPADOMAIN-COM/certmap.conf 
[...]
certmap default default
[...]
default:DNComps
default:FilterComps uid
certmap ipaca CN=Certificate Authority,O=IPADOMAIN.COM
ipaca:CmapLdapAttr seeAlso
ipaca:verifycert on

This means that when the LDAP server receives an authentication request with a certificate issued by the CA CN=Certificate Authority,O=IPADOMAIN.COM, it will look for users that contain a seeAlso attribute equal to the subject of the certificate, and the user entry must contain the certificate in the usercertificate attribute (verifycert: on).

With a default config, the ‘subsystemCert cert-pki-ca‘ is mapped to the user uid=pkidbuser,ou=people,o=ipaca. So let’s compare the user entry and the certificate:

$ ldapsearch -LLL -D 'cn=directory manager' -W -b uid=pkidbuser,ou=people,o=ipaca userCertificate description seeAlso
Enter LDAP Password: 
dn: uid=pkidbuser,ou=people,o=ipaca
userCertificate:: MIID...uwab3
description: 2;4;CN=Certificate Authority,O=IPADOMAIN.COM;CN=CA Subsystem,O=IPADOMAIN.COM
seeAlso: CN=CA Subsystem,O=IPADOMAIN.COM


$ sudo certutil -L -d /etc/pki/pki-tomcat/alias -n 'subsystemCert cert-pki-ca' -a
-----BEGIN CERTIFICATE-----
MIID...e5QAR
-----END CERTIFICATE-----

The certificate in the userCertificate attribute is different from the one in the NSS database! This can also be seen by comparing the serial number with the value from the ldap entry (in description: 2;<serial>;<issuer>;<subject>):

$ sudo certutil -L -d /etc/pki/pki-tomcat/alias -n 'subsystemCert cert-pki-ca' | grep Serial
 Serial Number: 1341718541 (0x4ff9000d

This explains why pki-tomcat could not authenticate to the LDAP server. The fix consists in updating the LDAP entry with the right certificate (and do not forget to update the description attribute with the right serial number!):

$ cat updatecert.ldif
dn: uid=pkidbuser,ou=people,o=ipaca
changetype: modify
replace: usercertificate
usercertificate::MII... <here put the new cert in a single line. The double colon :: is important as the format is binary>
-
replace: description
description: 2;<here put the new serial number>;CN=Certificate Authority,O=IPADOMAIN.COM;CN=CA Subsystem,O=IPADOMAIN.COM


$ ldapmodify -D "cn=directory manager" -W -f updatecert.ldif

But we still do not know the root cause for the inconsistency between the NSS database /etc/pki/pki-tomcat/alias and the user entry for uid=pkidbuser. This could be described in another blog post (for the impatients, the automatic renewal of the certificate failed to update the LDAP server entry…)

Troubleshooting: mapping between a SmartCard certificate and an IdM user

Authentication with a SmartCard may fail when the SmartCard certificate is not linked to any IdM user, or to a user different from the one specified on the console.

In order to find which user is associated to a given SmartCard certificate, you can run the following command:

ipaclient$ ipa certmap-match cert.pem
--------------
1 user matched
--------------
 Domain: IPADOMAIN.COM
 User logins: demosc1
----------------------------
Number of entries returned 1
----------------------------

If the result is not what you were expecting, you need first to check how certificates are mapped to users.

By default, a certificate is associated to a user when the user entry contains the full certificate in its usercertificate attribute. But this behavior can be modified by defining certificate mapping rules:

ipaclient$ ipa certmaprule-find
-------------------------------------------
1 Certificate Identity Mapping Rule matched
-------------------------------------------
 Rule name: rulesmartcard
 Mapping rule: (ipacertmapdata=X509:<I>{issuer_dn}<S>{subject_dn})
 Matching rule: <ISSUER>CN=Smart Card CA,O=EXAMPLE.ORG
 Enabled: FALSE
----------------------------
Number of entries returned 1
----------------------------

 

Mapping with full certificate content

When the mapping is based on the full certificate content, you can check if the user entry contains the certificate:

root@ipaclient$ ipa user-show demosc1
 User login: demosc1
[...]
Certificate: MIIC...

If it is not the case, associate the certificate with the user entry using:

ipaclient$ CERT=`cat cert.pem | tail -n +2 | head -n -1 | tr -d '\r\n'`
ipaclient$ ipa user-add-cert demosc1 --certificate $CERT

Once this is done, you may need to clear sssd cache to force SSSD to reload the entries before retrying ipa certmap-match:

ipaclient$ sudo sss_cache -E

 

Flexible mapping with certificate identity mapping rule

When the mapping is based on certificate mapping rules, the same tool ipa certmap-match can be used to check which user entry is associated to a certificate. When the result is not what you expect, you can enable sssd domain logs by adding the following in /etc/sssd/sssd.conf on IdM master:

[domain/ipadomain.com]
...
debug_level = 9

then restart sssd with

root@ipaserver$ systemctl restart sssd

The logs will be located in /var/log/sssd/sssd_ipadomain.log.

 

Check that the certificate identity mapping rules are properly loaded

When sssd is restarted, it reads the mapping rules and should print the following in /var/log/sssd/sssd_ipadomain.log:

[sssd[be[ipadomain.com]]] [sss_certmap_init] (0x0040): sss_certmap initialized.
[sssd[be[ipadomain.com]]] [ipa_certmap_parse_results] (0x4000): Trying to add rule [rulesmartcard][-1][<ISSUER>CN=Smart Card CA,O=EXAMPLE.ORG][(ipacertmapdata=X509:<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500})].

If the rule has an invalid syntax, you will see instead:

[sssd[be[ipadomain.com]]] [sss_certmap_init] (0x0040): sss_certmap initialized.
[sssd[be[ipadomain.com]]] [ipa_certmap_parse_results] (0x4000): Trying to add rule [rulesmartcard][-1][<ISSUER>CN=Smart Card CA,O=EXAMPLE.ORG][(ipacertmapdata=X509:<I>{issuer_dn!x509}<S>{subject_dn})].
[sssd[be[ipadomain.com]]] [parse_template] (0x0040): Parse template invalid.
[sssd[be[ipadomain.com]]] [parse_ldap_mapping_rule] (0x0040): Failed to add template.
[sssd[be[ipadomain.com]]] [parse_mapping_rule] (0x0040): Failed to parse LDAP mapping rule.
[sssd[be[ipadomain.com]]] [ipa_certmap_parse_results] (0x0020): sss_certmap_add_rule failed for rule [rulesmartcard], skipping. Please check for typos and if rule syntax is supported.
[sssd[be[ipadomain.com]]] [ipa_subdomains_certmap_done] (0x0040): Unable to parse certmap results [22]: Invalid argument
[sssd[be[ipadomain.com]]] [ipa_subdomains_refresh_certmap_done] (0x0020): Failed to read certificate mapping rules [22]: Invalid argument

The log shows that the rule named rulesmartcard is invalid. Check the rule (see man page for sss-certmap for the supported syntax) and fix if needed:

ipaclient$ ipa certmaprule-show rulesmartcard
 Rule name: rulesmartcard
 Mapping rule: (ipacertmapdata=X509:<I>{issuer_dn!x509}<S>{subject_dn})
 Matching rule: <ISSUER>CN=Smart Card CA,O=EXAMPLE.ORG
 Enabled: TRUE
ipaclient$ ipa certmaprule-mod rulesmartcard --maprule '(ipacertmapdata=X509:<I>{issuer_dn}<S>{subject_dn})'

 

Check that the matching rule corresponds to the certificate

When SSSD tries to associate the certificate to a user, it starts by finding which rule can be applied based on the matching rule (for instance rulesmartcard applies to all certificates issued by CN=Smart Card CA,O=EXAMPLE.ORG because its matching rule is <ISSUER>CN=Smart Card CA,O=EXAMPLE.ORG).

If no matching rule applies to the certificate, SSSD will not be able to associate the certificate with a user, and will display the following in /var/log/sssd/sssd_ipadomain.log:

[sssd[be[ipadomain.com]]] [sss_cert_derb64_to_ldap_filter] (0x0040): Certificate does not match matching-rules.

In this case, you need to create or modify an identity mapping rule, so that the match rule applies to your certificate. See sss-certmap man page for the supported syntax of the –matchrule option of ipa certmaprule-add command.

Check that the expected certificate identity mapping rule is used

When SSSD tries to find the user associated to the certificate, you will see the following logs in /var/log/sssd/sssd_ipadomain.log:

[sssd[be[ipadomain.com]]] [dp_get_account_info_handler] (0x0200): Got request for [0x14][BE_REQ_BY_CERT][cert=MII..]
...
[sssd[be[ipadomain.com]]] [sdap_search_user_next_base] (0x0400): Searching for users with base [cn=accounts,dc=ipadomain,dc=com]
[sssd[be[ipadomain.com]]] [sdap_print_server] (0x2000): Searching 10.34.58.20:389
[sssd[be[ipadomain.com]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(ipacertmapdata=X509:<I>O=EXAMPLE.ORG,CN=Smart Card CA<S>CN=test,O=EXAMPLE.ORG)(objectclass=posixAccount)(uid=*)(&(uidNumber=*)(!(uidNumber=0))))][cn=accounts,dc=ipadomain,dc=com].
...
[sssd[be[ipadomain.com]]] [sdap_search_user_process] (0x0400): Search for users, returned 0 results.

The logs show the LDAP search performed by SSSD: IP address of the LDAP server, base and search filter. Carefully review this information and compare with what you would expect.

Check that the mapping rule defines a valid search filter

If the rule cannot be transformed to a valid search filter, you will see in /var/log/sssd/sssd_ipadomain.log:

[sssd[be[ipadomain.com]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(ipacertmapdata=X509:<I>O=EXAMPLE.ORG,CN=Smart Card CA<S>CN=test,O=EXAMPLE.ORG(objectclass=posixAccount)(uid=*)(&(uidNumber=*)(!(uidNumber=0))))][cn=accounts,dc=ipadomain,dc=com].
[...]
[sssd[be[ipadomain.com]]] [sdap_get_generic_ext_step] (0x0080): ldap_search_ext failed: Bad search filter

If it is the case, you need to fix the certmap rule using

ipaclient$ ipa certmaprule-mod rulesmartcard –maprule …

 

 

Troubleshooting: authentication to the system console or Gnome Desktop Manager of an IdM host with a SmartCard

IdM allows to authenticate to an IdM enrolled-host by providing a SmartCard certificate instead of a username/password. The below steps are based on system console authentication but the process is similar when using Gnome desktop  login authentication.

When the authentication fails, the issue usually comes from a wrong configuration of the IdM system for SmartCard, or of PKINIT.

 

Configuration of the IdM host for SmartCard authentication

If the console does not even prompt for the SmartCard PIN, chances are high that the system was not properly configured for SmartCard authentication.

SSSD configuration for smart card

Check that /etc/sssd.conf contains

[pam]
pam_cert_auth = True

If you need to update the file, do not forget to restart sssd with

root@ipaclient$ systemctl restart sssd

 

SmartCard CA must be trusted

Check that the SmartCard CA is trusted in the /etc/pki/nssdb database:

root@ipaclient$ certutil -L -d /etc/pki/nssdb/

Certificate Nickname Trust Attributes     SSL,S/MIME,JAR/XPI

SmartCardCA                               CT,C,C

If the CA is not present, add it using:

root@ipaclient$ certutil -A -d /etc/pki/nssdb -n SmartCardCA -t CT,C,C -i ca.pem

 

IdM host PKCS#11 module

Check that the IdM host is properly configured for Smart Cards. The opensc package must be installed, the the SmartCard daemon must be running, and the PKCS#11 module must be loaded

root@ipaclient$ dnf install opensc
root@ipaclient$ systemctl start pcscd.service pcscd.socket
root@ipaclient$ modutil -dbdir /etc/pki/nssdb -add "OpenSC" -libfile /usr/lib64/opensc-pkcs11.so

 

Configuration for PKINIT

If the console prompts for the SmartCard PIN but displays

ipaclient login: demosc1
Pin for PIV Card:
Login incorrect

it is possible that the authentication fails trying to acquire a Kerberos ticket with PKINIT. In this case, login with username/password to the IdM host and try to manually perform kinit in order to get more information:

root@ipaclient$ kinit -X X509_user_identity='PKCS11:opensc-pkcs11.so' demosc1

 

If  the command outputs the following:

kinit: Pre-authentication failed: Failed to verify own certificate (depth 1): self signed certificate in certificate chain while getting initial credentials

then check the content of /etc/krb5.conf on the IdM host. The realms section must contain a configuration for ipadomain with pkinit_anchors:

[realms]
 IPADOMAIN.COM = {
 pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem
 pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem

}

The file defined in pkinit_anchors must exist, be readable and contain the certificate of the CA which signed the SmartCard certificate. If it is not the case, run the following commands on any IPA server:

root@ipaserver$ ipa-cacert-manage install -n SmartCardCA -t CT,C,C -p $DM_PWD ca.pem
root@ipaserver$ ipa-certupdate

And run the ipa-certupdate command on all IdM hosts in order to download the certificate.

If the kinit command output the following:

kinit: Certificate mismatch while getting initial credentials

check that the SmartCard certificate is associated to the username provided in the console (see mapping between a SmartCard certificate and an IdM user).

Troubleshooting: ssh to an IdM host with a SmartCard

IdM allows to perform ssh from a non-enrolled host into an IdM enrolled host, using Smart Card authentication instead of ssh authorized keys. The ssh command would be the following to log as demosc1 into the host ipaclient.ipadomain.com:

localuser@localhost$ ssh -I /usr/lib64/opensc-pkcs11.so -l demosc1 ipaclient.ipadomain.com
Enter PIN for 'PIV_II (PIV Card Holder pin)':

The -I option specifies a PKCS#11 shared library, and -l the username on the remote host.

 

Configuration of the local host

First check that the local host is properly configured for Smart Cards. The opensc package must be installed, and the the SmartCard daemon must be running.

localuser@localhost$ sudo dnf install opensc
localuser@localhost$ sudo systemctl start pcscd.service pcscd.socket

 

Configuration of the remote (IdM) host

When IdM is properly configured, ssh will prompt for the SmartCard PIN and authenticate the user. If there is an issue with the certificate, ssh will revert to another authentication type (private keys or username/password).

In this case, enable debug logs for ssh authentication on IdM host. Edit /etc/sssd/sssd.conf and add the following line in [ssh] section:

[ssh]
debug_level = 9

then restart sssd using

root@ipaclient$ systemctl restart sssd

The logs will be located on the IdM host in /var/log/sssd/sssd_ssh.log.

 

The Smart Card CA is not trusted by SSSD

If you see the following in /var/log/sssd/sssd_ssh.log:

[sssd[ssh]] [cert_to_ssh_key] (0x0020): CERT_VerifyCertificateNow failed [-8179].
[sssd[ssh]] [get_valid_certs_keys] (0x0040): cert_to_ssh_key failed, ignoring.

then it means that the CA that signed the Smart Card certificate is not trusted. The trusted certs are stored in /etc/pki/nssdb and can be found using:

root@ipaclient$ certutil -L -d /etc/pki/nssdb

Certificate Nickname Trust Attributes     SSL,S/MIME,JAR/XPI

SmartCardCA                               CT,C,C

 

If the CA cert is missing, add it using

root@ipaclient$ certutil -A -d /etc/pki/nssdb -n SmartCardCA -t CT,C,C -i ca.pem

 

The user is not an IdM user

If the ssh operation does not log any line in /var/log/sssd/sssd_ssh.log, it probably means that the supplied user name is not a user defined in IdM. You can check with:

root@ipaclient$ ipa user-find demosc1
---------------
0 users matched
---------------
----------------------------
Number of entries returned 0
----------------------------

Check that you provided the right user name, or define an IdM user and associate the SmartCard certificate with this user.

 

The certificate is not mapped to the IdM user

If you see the following in /var/log/sssd/sssd_ssh.log:

Found 1 entries in domain ipadomain.com

but the authentication fails, check that the SmartCard certificate is associated to the provided username (refer to mapping between a SmartCard certificate and an IdM user)

FreeIPA: troubleshooting SmartCard authentication

RHEL 7.4 beta is now available, delivering a new version of IPA which contains the support for Smart Card authentication. This feature allows to use a certificate contained in a SmartCard in order to login to IdM WebUI, to ssh to an IdM-enrolled host, or to login to the console or Gnome Desktop Manager of an IdM-enrolled host.

This feature is really powerful but may also seem difficult to troubleshoot. I will explain where to look for additional information when authentication fails, and how to fix the most common issues.

The information is split into posts specific to each authentication method:

 

 

Use an alternate identity for EUS configuration

During EUS setup, the administrator needs to provide a user DN and password to authenticate to the directory server (for instance during the dbca step, or while using eusm or Enterprise Manager).

 

In some companies, the database and the LDAP server are managed by different teams and the LDAP administrator credentials cannot be provided to the database administrator. In this case, it is possible to administer EUS using an alternate identity, i.e not cn=directory manager. The requirements for this alternate identity are the following:

  • the user must be a member of the group cn=OracleContextAdmins,cn=Groups,cn=OracleContext,<base DN>
  • the user must have the password-reset privilege

 

Here is an example of configuration steps: create a input.ldif file with the following content

$ cat input.ldif
dn: cn=eusadmin,cn=oraclecontext
changetype: add
objectclass: inetorgperson
cn: eusadmin
sn: eusadmin
uid: eusadmin
userpassword: password

dn: cn=eusadmin,,cn=oraclecontext
changetype: modify
add: ds-privilege-name
ds-privilege-name: password-reset

dn: cn=OracleContextAdmin,cn=groups,cn=OracleContext,dc=example,dc=com
changetype: modify
add: uniquemember
uniquemember: cn=eusadmin,cn=oraclecontext

And perform

$ $ORACLE_HOME/bin/ldapmodify -h localhost -p 1389 -D "cn=directory manager" -w password -f input.ldif

Note 1: this EUS admin user can be stored in your preferred location inside the DIT, but NOT BELOW cn=oraclecontext,<base DN>. For instance, cn=eusadmin,ou=people,dc=example,dc=com is valid, but cn=eusadmin,cn=oraclecontext,dc=example,dc=com is NOT valid.

Note 2: the EUS admin user does not have to be named eususer.

Note 3: if OUD is installed as a proxy server, then the EUS admin user must be stored locally inside OUD proxy, and for instance cn=eususer,cn=oraclecontext would be a valid location.

How to configure EUS + SSL authentication with OUD

During an EUS authentication, there are 2 communication channels: one between the sql client and the database, and another one between the database and the LDAP server. In a previous post, I explained that the database-to-OUD communication can be authenticated either through user/password or SSL.

EUS_auth

The sql client-to-database connection also supports multiple authentication methods:

  • user/password
  • SSL
  • Kerberos (described in this post)

In this post, I will explain how to configure SSL authentication. Note that SSL authentication is usually used in conjunction with DB-to-OUD SSL authentication. This post assumes that DB-to-OUD SSL authentication has already been set up as described there and that the database already has a wallet containing the DB certificate.

Using sqlplus, it is possible to connect to the DB using a client certificate instead of username/password. In order to do this, the DB must be configured with an SSL listener, and the sqlplus client must be configured to use a client certificate.

  1. Configure the database to allow SSL authentication:
    The file sqlnet.ora located in $ORACLE_HOME/network/admin must be modified to look like the following:

    NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
      
    ADR_BASE = <$ORACLE_BASE>
    
    #ADDED FOR SSL 
    SQLNET.AUTHENTICATION_SERVICES= (TCPS, BEQ)
    SSL_CLIENT_AUTHENTICATION = TRUE
    WALLET_LOCATION = 
      (SOURCE =
        (METHOD = FILE)
        (METHOD_DATA =
          (DIRECTORY = <$ORACLE_BASE>/admin/<$ORACLE_SID>/wallet)
        )
      )
  2. Configure a SSL listener on the database:
    The listeners are defined in the configuration file listener.ora, located in $ORACLE_HOME/network/admin. The content of this file defines the port and protocol used by the listener, and the location of the wallet that will store the database certificate.

    LISTENER =
      (DESCRIPTION_LIST =
        (DESCRIPTION =
          (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
          (ADDRESS = (PROTOCOL = TCP)(HOST = <hostname>)(PORT = 1521))
    #ADDED FOR SSL
          (ADDRESS = (PROTOCOL = TCPS)(HOST = <hostname>)(PORT = 1575))
        )
      )
    
    ADR_BASE_LISTENER = <$ORACLE_BASE>
    
    #ADDED FOR SSL
    WALLET_LOCATION = (SOURCE=
      (METHOD = FILE)
        (METHOD_DATA =
          (DIRECTORY=<$ORACLE_BASE>/admin/<$ORACLE_SID>/wallet)
        )
      )
    
  3. Restart the listener:
    the modification of listeners.ora requires to restart the database listener with the following commands

    $ $ORACLE_HOME/bin/lsnrctl stop
    $ $ORACLE_HOME/bin/lsnrctl start
  4. Configure the sql client to use SSL authentication:

    The sql client reads its configuration from sqlnet.ora and tnsnames.ora. By default, those files are located in the same location as the DB configuration files ($ORACLE_HOME/network/admin), which can cause issues because the client and the server use a different wallet. In order to avoid configuration issues, it is recommended to have separate configuration files. To do this, the environment variable TNS_ADMIN is used to configure the path containing the client configuration files:

    $ setenv TNS_ADMIN /path/to/files
    

    or

    $ export TNS_ADMIN=/path/to/files
    

    Then the file tnsnames.ora will define how to reach the database using SSL:

    $ cat /path/to/files/tnsnames.ora 
    ORCL11G =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCPS)(HOST = <hostname>)(PORT = 1575))
        (CONNECT_DATA =
          (SERVER = DEDICATED)
          (SERVICE_NAME = orcl11g)
        )
      )
    

    And finally the file sqlnet.ora defines the SSL configuration (wallet location…):

    $ cat sqlnet.ora 
    NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
    SQLNET.AUTHENTICATION_SERVICES = (TCPS,BEQ)
    SSL_CLIENT_AUTHENTICATION = TRUE 
    WALLET_LOCATION =
      (SOURCE =
        (METHOD = FILE)
        (METHOD_DATA =
          (DIRECTORY = /path/to/client/wallet)
        )
      )
  5. Create the client wallet and the client certificate:
    The client wallet will store the client certificate as well as the certificates trusted by the client (i.e. the server certificate).
    The client certificate must contain a DN that corresponds to a LDAP entry on OUD server. The following commands create a client wallet, then add a self-signed certificate to the wallet for the user cn=Joe, and finally export the self-signed certificate to a file.

    $ orapki wallet create -wallet /path/to/client/wallet -pwd <password> -auto_login
    
    $ orapki wallet add -wallet /path/to/client/wallet -dn cn=Joe,ou=users,dc=example,dc=com -keysize 1024 -self_signed -validity 365 -pwd <password>
    
    $ orapki wallet export -wallet /path/to/client/wallet -dn cn=Joe,ou=users,dc=example,dc=com -cert joe-cert.txt
    

  6. Add the client certificate to the DB wallet:
    the database must trust the client certificate in order to accept SSL connections. As the above steps created a self-signed user certificate, the client certificate has to be imported as a trusted cert in the DB wallet.

    $ orapki wallet add -wallet <PathToDBWallet> -cert joe-cert.txt -trusted_cert -pwd <password>
    
  7. Add the DB certificate to the client wallet:
    the client must trust the DB certificate. If the DB certificate is a self-signed certificate, this means that the DB cert must be added to the client wallet.

    $ orapki wallet add -wallet /path/to/client/wallet -cert db-cert.txt -trusted_cert -pwd <password>
  8. Allow EUS to accept SSL connections between the client and the database:

     log in to Enterprise Manager: https://<hostname>:1158/em

    In the “Server” tab, select “Enterprise User Security” in the “Security” section, then “Manage Enterprise Domain” and click on “Configure”. In the “Configuration” tab, select the authentication methods that you want to allow between the client and the DB: Password, SSL, Kerberos.

  9. Test the SSL connection between the client and the database:

    The following command reads the sql configuration files, extracts the path to the client wallet, then connects to the DB using the certificate found in the client wallet:

    $ export TNS_ADMIN=/path/to/files
    $ sqlplus /@orcl11g
    
    SQL*Plus: Release 11.2.0.2.0 Production on Wed Mar 28 11:18:57 2012
    
    Copyright (c) 1982, 2010, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    
    SQL>

Once authenticated with the client certificate, the enterprise user will be mapped to a schema exactly as a user/password authenticated user. EUS will also find the groups for the LDAP user and grant the corresponding roles to the EUS user.

How to configure EUS + Kerberos authentication with OUD

During an EUS authentication, there are 2 communication channels: one between the sql client and the database, and another one between the database and the LDAP server. In a previous post, I explained that the database-to-OUD communication can be authenticated either through user/password or SSL.

EUS_auth

The sql client-to-database connection also supports multiple authentication methods:

  • user/password
  • SSL
  • Kerberos

In this post, I will explain how to configure Kerberos authentication. I am assuming that you already have a Kerberos server up and running.

 

  1. Create a Kerberos Principal for the Database:
    The database service needs to have a corresponding Kerberos principal in the Kerberos server. If your Kerberos server is running on a Linux machine, this can be done with the kadmin utility. In my example, the kerberos administrator is kws/admin and creates a principal for the database having ORACLE_SID=orcl11g, running on host dbhost, with a Kerberos realm EXAMPLE.COM:

    $ kadmin -p kws/admin
    Authenticating as principal kws/admin with password.
    Password for kws/admin@EXAMPLE.COM: 
    kadmin:  add_principal -randkey orcl11g/dbhost
    WARNING: no policy specified for orcl11g/dbhost@EXAMPLE.COM; defaulting to no policy
    Principal "orcl11g/dbhost@EXAMPLE.COM" created.
    kadmin: ktadd -k /tmp/orcl11g.keytab orcl11g/dbhost@EXAMPLE.COM
    Entry for principal orcl11g/dbhost@EXAMPLE.COM with kvno 2, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/tmp/orcl11g.keytab.
    Entry for principal orcl11g/dbhost@EXAMPLE.COM with kvno 2, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/tmp/orcl11g.keytab.
    Entry for principal orcl11g/dbhost@EXAMPLE.COM with kvno 2, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/tmp/orcl11g.keytab.
    Entry for principal orcl11g/dbhost@EXAMPLE.COM with kvno 2, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/tmp/orcl11g.keytab.
    kadmin:  exit

    The add_principal command creates a principal, and the ktadd command creates and stores the secret key in the file /tmp/orcl11g.keytab.

  2. Copy the keytab to the database host:
    $ scp /tmp/orcl11g.keytab oracle@dbhost:/path/to/orcl11g.keytab
  3. Create a Kerberos principal for the EUS user:
    The user that will use sqlplus also needs to be provisioned in the KDC. In the example, the user principal name is eususer@EXAMPLE.COM:

    $ kadmin -p kws/admin
    Authenticating as principal kws/admin with password.
    Password for kws/admin@EXAMPLE.COM: 
    kadmin:  add_principal eususer
    WARNING: no policy specified for eususer@EXAMPLE.COM; defaulting to no policy
    Enter password for principal "eususer@EXAMPLE.COM": 
    Re-enter password for principal "eususer@EXAMPLE.COM": 
    Principal "eususer@EXAMPLE.COM" created.
    kadmin:  exit
    $
  4. Configure the database to allow Kerberos authentication:
    By default the database supports only user/password authentication. In order to allow Kerberos authentication, the file sqlnet.ora (located in $ORACLE_HOME/network/admin) needs to be modified to look like the following:

    $ cat sqlnet.ora
    NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
    ADR_BASE = /export/home/oracle/app/oracle
    
    #ADDED FOR KERBEROS
    SQLNET.AUTHENTICATION_SERVICES= (BEQ, KERBEROS5)
    SQLNET.AUTHENTICATION_KERBEROS5_SERVICE=orcl11g
    SQLNET.KERBEROS5_CONF=/etc/krb5.conf
    SQLNET.KERBEROS5_KEYTAB=/path/to/orcl11g.keytab
    SQLNET.KERBEROS5_CONF_MIT=true
    
    
  5. Configure the database host as a Kerberos client:
    Edit /etc/krb5.conf and set the values for the Kerberos server in kdc and admin_server properties. In my example, the Kerberos server is running on kdc_host.fr.oracle.com:

    [...]
    [libdefaults]
     default_realm = EXAMPLE.COM
     dns_lookup_realm = false
     dns_lookup_kdc = false
     ticket_lifetime = 24h
     forwardable = yes
    [realms]
     EXAMPLE.COM = {
      kdc = kdc_host.fr.oracle.com
      admin_server = kdc_host.fr.oracle.com
     }
    [domain_realm]
     .example.com = EXAMPLE.COM
     example.com = EXAMPLE.COM
     .fr.oracle.com = EXAMPLE.COM
     fr.oracle.com = EXAMPLE.COM
    [...]

    You can test that the database host is properly configured by trying to get a Kerberos ticket-granting ticket for the database with the kinit utility:

    $ kinit -k -t /path/to/orcl11g.keytab orcl11g/dbhost@EXAMPLE.COM
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_54321
    Default principal: orcl11g/dbhost@EXAMPLE.COM
    Valid starting Expires Service principal
    03/03/16 11:35:50 03/03/16 21:35:50 krbtgt/EXAMPLE.COM@EXAMPLE.COM
     renew until 03/04/16 11:35:50
    Kerberos 4 ticket cache: /tmp/tkt54321
    klist: You have no tickets cached
    $
  6. Configure the sql client host as a Kerberos client:
    this step is the same as the previous one (edition of /etc/krb5.conf), except that it must be done on the host where the sql client is running. You can test that the Kerberos configuration is working by getting a ticket-granting ticket for the Enterprise user:

    $ kinit eususer
    Password for eususer@EXAMPLE.COM: 
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_54321
    Default principal: eususer@EXAMPLE.COM
    
    Valid starting     Expires            Service principal
    03/29/12 16:32:41  03/30/12 02:32:41  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 03/30/12 16:32:38
    
    
    Kerberos 4 ticket cache: /tmp/tkt54321
    klist: You have no tickets cached
    $
    
  7. Configure the sql client to authenticate with Kerberos:
    Create a directory to store the SQL client configuration, and define the environment variable TNS_ADMIN to point to this directory:

    $ mkdir -p /path/for/sql/config
    $ export TNS_ADMIN=/path/for/sql/config

    In this directory, create a tnsnames.ora file defining how to contact the database:

    $ cat $TNS_ADMIN/tnsnames.ora
    ORCL11G = (DESCRIPTION =
     (ADDRESS = (PROTOCOL = TCP)(HOST = dbhost)(PORT = 1521))
     (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = orcl11g))
     )

    In the same directory, create a sqlnet.ora file defining the connection method to the database:

    $ cat $TNS_ADMIN/sqlnet.ora 
    NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
    SQLNET.AUTHENTICATION_SERVICES = (BEQ,KERBEROS5)
    SQLNET.KERBEROS5_CONF=/etc/krb5.conf
    SQLNET.KERBEROS5_CONF_MIT=true
  8. Link the LDAP user entry to the Kerberos principal:
    The Kerberos principal that will be used with SQL client must correspond to a LDAP user. In order to do this, you have 2 options:

    • if your LDAP users have the objectclass orcluserV2, you can add the attribute krbprincipalname to the user entry. For instance, if Kerberos principal eususer must correspond to LDAP entry cn=user,dc=example,dc=com, you must add krbprincipalname: eususer@EXAMPLE.COM to the entry.
      EUS_kerberos_auth
    • if your LDAP users do not have the objectclass orcluserV2, you can user another attribute to store the Kerberos principal name. In this case, you must declare this attribute by setting the attribute orclcommonkrbprincipalattribute of the entry cn=Common,cn=Products,cn=OracleContext,dc=example,dc=com. For instance:
      dn: cn=Common,cn=Products,cn=OracleContext,dc=example,dc=com
      orclcommonkrbprincipalattribute: mail

      will correspond to a user entry

       dn: cn=user,dc=example,dc=com
       mail: eususer@EXAMPLE.COM
  9. Test the connection:

    The user must first get a Kerberos ticket-granting ticket, then call sqlplus with the / option that specifies to use the Kerberos TGT:

    $ kinit eususer
    Password for eususer@EXAMPLE.COM: 
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_54321
    Default principal: eususer@EXAMPLE.COM
    
    Valid starting     Expires            Service principal
    03/29/12 16:47:29  03/30/12 02:47:29  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 03/30/12 16:47:27
    
    
    Kerberos 4 ticket cache: /tmp/tkt54321
    klist: You have no tickets cached
    $ sqlplus /@orcl11g
    
    SQL*Plus: Release 11.2.0.2.0 Production on Thu Mar 29 16:47:35 2012
    
    Copyright (c) 1982, 2010, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    
    SQL> exit
    Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_54321
    Default principal: eususer@EXAMPLE.COM
    
    Valid starting     Expires            Service principal
    03/29/12 16:47:29  03/30/12 02:47:29  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 03/30/12 16:47:27
    03/29/12 16:47:35  03/30/12 02:47:29  orcl11g/dbhost@EXAMPLE.COM
        renew until 03/30/12 16:47:27
    
    
    Kerberos 4 ticket cache: /tmp/tkt54321
    klist: You have no tickets cached
    $ 
    
    

    You can see using klist utility that after the sql connection, the user has a second ticket corresponding to the database service.

Troubleshooting tips:

If your setup is not working, you can enable Kerberos logs by adding the following in the /etc/krb5.conf of the Kerberos server:

[logging]
 kdc = FILE:/var/log/krb5kdc.log

then restart the KDC to apply the changes:

$ sudo service krb5-kdc restart

The problem can be linked to the host names (if the database hostname is defined as a fully-qualified-domain-name but the database service principal uses only the short name or vice-versa). The logs will show you which service principal is used by the database and if there is a mismatch.

Another common problem is when the database is not able to find any user entry matching the Kerberos principal from the ticket. In this case, you can have a look at OUD access log and check the search done by the database to find the user entry. This will be a search equivalent to:

$ ldapsearch -b <orclcommonusersearchbase> "(<orclcommonkrbprincipalattribute>=<krb_principal from the ticket>)"

You need to make sure that the database is using the proper search base and search filter. The search base is configured in the entry cn=Common,cn=Products,cn=OracleContext,dc=example,dc=com, in the attribute orclcommonusersearchbase. To find its value, you can perform the following search operation:

$ OracleUnifiedDirectory/bin/ldapsearch -h $LDAPSERVER -p $PORT -b cn=common,cn=products,cn=oraclecontext,$BASEDN  "(objectclass=*)" orclcommonusersearchbase
dn: cn=Common,cn=Products,cn=OracleContext,dc=example,dc=com
orclcommonusersearchbase: ou=people,dc=example,dc=com