freeipa/doc/designs/client-install-pkinit.md
Christian Heimes dbebed2e3a Add PKINIT support to ipa-client-install
The ``ipa-client-install`` command now supports PKINIT for client
enrollment. Existing X.509 client certificates can be used to
authenticate a host.

Also restart KRB5 KDC during ``ipa-certupdate`` so KDC picks up new CA
certificates for PKINIT.

*Requirements*

- The KDC must trust the CA chain of the client certificate.
- The client must be able to verify the KDC's PKINIT cert.
- The host entry must exist. This limitation may be removed in the
  future.
- A certmap rule must match the host certificate and map it to a single
  host entry.

*Example*

```
ipa-client-install \
    --pkinit-identity=FILE:/path/to/cert.pem,/path/to/key.pem \
    --pkinit-anchor=/path/to/kdc-ca-bundle.pem
```

Fixes: https://pagure.io/freeipa/issue/9271
Fixes: https://pagure.io/freeipa/issue/9269
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-11-16 14:32:05 +02:00

7.9 KiB

IPA client enrollment with PKINIT

This design document proposes PKINIT as an additional authentication mechanism for ipa-client-install, ticket https://pagure.io/freeipa/issue/9271.

Overview

PKINIT is an authentication mechanism for Kerberos that uses X.509 certificates and private keys to authenticate Kerberos KDC server to client and optionally clients to the server. Mutual authentication is almost the same as mTLS with TLS server and client certificates in HTTPS.

PKINIT can be used instead of user/password or OTP to authorize client enrollment. This enables admins to re-use existing host certificates to automate client installations.

Assumptions

  • The client machine has access to a X.509 certificate / key pair that uniquely identifies an account with necessary permissions to enroll the host. The certificate does not have to contain special extensions for PKINIT. It only requires an attribute that can be uniquely mapped to an account, e.g. subject alternative name (SAN) dNSName maps to FQDN of an existing host entry or RFC 822 name maps to an user account with enrollment privileges.
  • A certmap rule exists matches the certificate, and maps the unique identifier to a single account like an existing host entry or user with enrollment privileges.
  • The certificate is signed by a CA chain which is known to and trusted by the Kerberos KDC server. This can be accomplished by installing the root CA and intermediate CAs as additional CA certificates to IPA with ipa-cacert-manage install on one IPA server, then running ipa-certupdate on every IPA servers.
  • The CA chain of the certificate and the CA chain of the Kerberos KDC server certificate are available on the host. On an IPA server, the file /var/lib/ipa-client/pki/kdc-ca-bundle.pem typically contains all necessary CAs.

How the certificates and CAs are generated and distributed and how host entries are created is out of scope for this document. The certificates and key can be provided as files or by a PKCS#11 provider like OpenSC from a smart card or p11-kit proxy from a remote PKCS#11 source.

Host self-enrollment

Host self-enrollment allows a host to enroll itself using a host-specific certificate. The approach use the fact that a host account has the necessary permissions to self-manage its host entry. A host entry must be pre-created by a privileged account and a certmap rule must map a unique identifier to a host entry.

For example a certmap rule like

$ ipa certmaprule-add pkinit-host \
    --matchrule '<ISSUER>CN=Certificate Authority,O=IPA.EXAMPLE' \
    --maprule='(fqdn={subject_dns_name})'

allows an host with hostname host.ipa.example and a certificate with properties like

Issuer: O = HMSIDM.TEST, CN = Certificate Authority
Subject: O = HMSIDM.TEST, CN = host.ipa.example
X509v3 extensions:
    X509v3 Subject Alternative Name:
        DNS:host.ipa.example

to enroll itself with a command like

$ ipa-client-install \
    --pkinit-identity=FILE:/path/to/cert.pem,/path/to/key.pem \
    --pkinit-anchor=FILE:/path/to/kdc-ca-bundle.pem \
    ...

A privileged account only has to pre-created its host entry with

$ ipa host-add host.ipa.example

first.

Privileged user account

A user account with e.g. Host Administrators privilege can be used to create and enroll new hosts.

Example certmap rule:

$ ipa certmaprule-add pkinit-user \
    --matchrule '<ISSUER>CN=Certificate Authority,O=IPA.EXAMPLE' \
    --maprule='(&(mail={subject_rfc822_name})(objectclass=inetorgperson))'

In this case you have to pass the principal name of the user account to ipa-client-install:

$ ipa-client-install \
    --pkinit-identity=FILE:/path/to/cert.pem,/path/to/key.pem \
    --pkinit-anchor=FILE:/path/to/kdc-ca-bundle.pem \
    -p enrollmentuser
    ...

New options for ipa-client-install

The ipa-client-install command is extended with two new options:

--pkinit-identity=IDENTITY specifies the PKINIT identity information. The option is mutually exclusive with --keytab and --password option. See man krb5.conf(5) for more information. Possible values are

  • FILE:/path/to/cert.pem,/path/to/key.pem or FILE:/path/to/combined.pem for certificate and private key in PEM format.
  • PKCS12:/path/to/file.p12 for PKCS#12 file with a certificate and private key.
  • PKCS11:... to use a PKCS#11 provider
  • DIR:/path/to/directory with *.crt and *.key files.

--pkinit-anchor=FILEDIR to load trust anchors (root and intermediate CA certs) for KDC server and host identity. FILE is either an absolute path to a PEM bundle (for example FILE:/etc/pki/tls/cert.pem) or to an OpenSSL hash directory (for example DIR:/etc/ssl/certs/). The option can be used multiple times to load trust anchors from several locations.

By default ipa-client-install attempts to authenticate with the host principal host/hostname@REALM. Use -p option to authenticate as a different account.

Example:

$ ipa-client-install \
    --pkinit-identity=FILE:/path/to/cert.pem,/path/to/key.pem \
    --pkinit-anchor=FILE:/path/to/kdc-ca-bundle.pem \
    ...

Testing

The ipa certmap-match command does not support hosts, yet. To test a rule and certificate, you can run kinit:

$ kinit \
    -X X509_user_identity=FILE:/path/to/cert.pem,/path/to/key.pem \
    -X X509_anchors=FILE:/path/to/kdc-ca-bundle.pem \
    host/host.ipa.example

Set the environment variable KRB5_CONFIG=/dev/stderr for additional debug information. On IPA servers the log file /var/log/krb5kdc.log contains information about cert authentication and filters:

Initializing IPA certauth plugin.
Doing certauth authorize for [host/host.ipa.example@IPA.EXAMPLE]
Got cert filter [(fqdn=host.ipa.example)]
PKINIT: freshness token received from host/host.ipa.example@IPA.EXAMPLE

The KDC caches certmap rules for 5 minutes. To test a new or modified certmap rule immediately, the KDC must be restarted with the command systemctl restart krb5kdc.service.

cert map rules

See SSSD: Certificate mapping and matching rules and man sss-certmap(5).

certmap matching rule

certmap matching rules use RFC 4514 string representation of subject and issuer distinguished names (DN) in LDAP order with NSS-style attribute type names. RFC 4514 is the successor to RFC 2253. LDAP order is reverse to X.509 order of relative distinguised names, so common name (CN) typically comes before organization and country.

  • Matching rules are regular expressions. Characters ^.[$()|*+?{\\ must be quoted, e.g. . becomes \..
  • Characters =#+,;<=>\ have special meaning in in RDN attribute values and may be escaped. A , becomes \,, which is then quoted again as \\,.
  • Some fields use different attribute type names than OpenSSL, e.g. emailAddress attributes is just E.

To match a cert with issuer DN O = "ACME, Inc.", CN = host.acme.example, emailAddress = info@acme.example, use the matching rule <I>^E=info@acme.example,CN=host.acme.example,O=ACME\\, Inc\.$.

certmap mapping rules

certmap mapping rules are used to associate a certificate with an account. Mapping rules are LDAP queries with templating, e.g. (fqdn={subject_dns_name}) uses the dNSName value from the certificate subject alternative name extension.

  • Combine the filter with (!(krbprincipalkey=*)) to prevent further PKINIT authenticate after the host has been enrolled: (&(fqdn={subject_dns_name})(!(krbprincipalkey=*)))
  • Use (!(memberof=cn=ipaservers,cn=hostgroups,cn=accounts,.*)) to prevent PKINIT as an IPA server host or (memberof=pkinit-hosts,cn=hostgroups,cn=accounts,.*) to limit PKINIT to hosts in a custom pkinit-hosts host group.