FreeIPA Dogtag Certs
- The IPA CA is Dogtag. Treat it like a CA: plan renewals, back it up, have two CA replicas.
- Use certmonger. Letting a cert expire because you forgot the renewal script is an unforced error certmonger prevents for free.
- Sub-CAs (
ipa ca-add) exist for scoping. Issue service certs from a sub-CA whose trust you can distribute without pushing the whole root. - For web-ish workloads that speak ACME, enable ACME on IPA and forget manual issuance.
- External-CA mode makes the IPA CA a sub of your corporate root. Decide before first install; changing it later is an outage.
- Renewing the IPA CA itself is a scheduled event, not an emergency. Know the date; test on a replica first.
The Dogtag model in IPA
When you install IPA with --setup-ca, you get:
- Dogtag PKI (
pki-tomcatd@pki-tomcat) running on loopback. - An IPA CA with subject
CN=Certificate Authority,O=EXAMPLE.INTERNALby default. - A certmonger tracking entry for the CA's own cert, so Dogtag's signing cert auto-renews.
- A small number of profiles you can issue against (
caIPAserviceCertby default, plusIECUserRoleset al.).
Sub-CAs (ipa ca-add)
Create a sub-CA when you want a trust domain narrower than "everything our IPA ever signs". For example: a sub-CA for internal mTLS that you can distribute to Kubernetes without also trusting every cert IPA issues.
kinit admin
# Create the sub-CA
ipa ca-add internal-mtls \
--subject "CN=Internal mTLS,O=EXAMPLE.INTERNAL" \
--desc "mTLS between internal services"
# See what exists
ipa ca-find
# Fetch the sub-CA cert to ship to consumers
ipa ca-show internal-mtls --out /etc/pki/ca-trust/source/anchors/internal-mtls.pem
update-ca-trust
Issuance is now parameterised by --ca=:
ipa cert-request /tmp/app.csr \
--principal HTTP/app1.example.internal \
--ca internal-mtls \
--profile caIPAserviceCert
Issuing service certs
Three steps: create the service principal, generate a CSR, request the cert.
1. Generate a CSR
# On the host that needs the cert
sudo -u app openssl req -new -newkey rsa:4096 -nodes \
-keyout /etc/pki/tls/private/app.key \
-out /tmp/app.csr \
-subj "/CN=app1.example.internal" \
-addext "subjectAltName=DNS:app1.example.internal,DNS:app.example.internal"
For modern workloads, prefer ECDSA P-256 or Ed25519 where supported:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-keyout /etc/pki/tls/private/app.key -out /tmp/app.csr \
-subj "/CN=app1.example.internal" \
-addext "subjectAltName=DNS:app1.example.internal"
2. Ensure the service principal exists
ipa service-add HTTP/app1.example.internal
# If this host is not the app's own, authorise the requester explicitly:
ipa service-add-host HTTP/app1.example.internal --hosts=deploy01.example.internal
3. Request the cert
ipa cert-request /tmp/app.csr \
--principal HTTP/app1.example.internal \
--profile caIPAserviceCert \
--ca ipa \
--certificate-out /etc/pki/tls/certs/app.pem
The returned cert chains to the IPA CA (or whatever sub-CA you asked for). Combine with the CA bundle if the consumer needs it:
ipa ca-show ipa --out /etc/pki/tls/certs/ipa-ca.pem
cat /etc/pki/tls/certs/app.pem /etc/pki/tls/certs/ipa-ca.pem \
> /etc/pki/tls/certs/app-fullchain.pem
Tracking with certmonger
Manual issuance is fine for a one-off. For anything that lives past a renewal cycle, track with certmonger so it renews itself.
sudo ipa-getcert request \
-K HTTP/app1.example.internal \
-D app1.example.internal -D app.example.internal \
-k /etc/pki/tls/private/app.key \
-f /etc/pki/tls/certs/app.pem \
-C "systemctl reload nginx" \
-r
| Flag | Meaning |
|---|---|
-K | Kerberos principal that identifies the service |
-D | Subject Alternative Name (DNS). Use once per SAN. |
-k, -f | Private key and cert paths certmonger will maintain |
-C | Command certmonger runs after each renewal (reload the consumer) |
-r | Auto-renew; the default but explicit is good |
-T <profile> | Pick a non-default profile |
-X <ca> | Pick a sub-CA |
Inspect and manage
sudo getcert list
sudo getcert list -i <request-id> # details for one request
sudo getcert resubmit -i <request-id> # force a renewal
sudo getcert stop-tracking -i <request-id> # stop certmonger from touching it
/var/log/messages (systemd: journalctl -u certmonger). When a renewal fails silently, this is the first place to look.
ACME on IPA
IPA has shipped an ACME endpoint for a while. If your consumer speaks ACME, this is the lowest-friction option — no keytabs, no service principals, just HTTP-01.
sudo ipa-acme-manage enable
sudo ipa-acme-manage status
# Directory URL to hand to your ACME client:
# https://ipa1.example.internal/acme/directory
Client side, with certbot:
certbot certonly --standalone \
--server https://ipa1.example.internal/acme/directory \
-d app1.example.internal \
--no-eff-email --agree-tos -m devops@example.internal
And with acme.sh:
acme.sh --issue -d app1.example.internal \
--server https://ipa1.example.internal/acme/directory \
--standalone
Restrictions:
- The requester must be able to prove control of the name. HTTP-01 needs port 80 reachable by the IPA server.
- Only DNS names already known to IPA (A/AAAA or a matching host entry) are signed by default.
- No EAB; authentication is "you solved the challenge".
Renewing the IPA CA
The CA signing cert has a lifetime. By default it is ~10 years, but early installs used shorter lifetimes; some regulated environments force shorter. You will renew eventually.
Check when
sudo ipa-certupdate # fetch current trust bundle
sudo getcert list | grep -E 'subject|expires' | head -40
# Or directly from Dogtag:
sudo openssl x509 -noout -dates \
-in /etc/pki/pki-tomcat/alias/ca_signing.crt
Renew (internal-CA mode)
# Certmonger already tracks the CA cert. Force it:
sudo ipa-cacert-manage renew --self-sign
sudo ipa-certupdate # push the new trust bundle to all clients via SSSD
Renew (external-CA mode)
# Step 1: generate a CSR for the IPA CA
sudo ipa-cacert-manage renew --external-ca
# This writes /var/lib/ipa/ca.csr. Hand it to your corporate root.
# Step 2: receive the signed cert + chain back, then:
sudo ipa-cacert-manage renew \
--external-cert-file=/tmp/ipa-ca.new.crt \
--external-cert-file=/tmp/corp-root.pem
sudo ipa-certupdate
External-CA mode
Decision at first ipa-server-install:
ipa-server-install --external-ca \
--realm EXAMPLE.INTERNAL --domain example.internal \
--setup-dns --auto-forwarders \
--ds-password 'REDACTED' --admin-password 'REDACTED' \
--unattended
# Installer pauses and emits /root/ipa.csr. Sign it with the corporate CA.
# Resume with the signed cert and the corporate chain:
ipa-server-install --external-cert-file=/root/ipa.crt \
--external-cert-file=/root/corp-root.pem
Trade-offs:
- Pro: Every cert IPA issues chains to your corporate root. Downstream consumers already trust it.
- Pro: Revocation story is unified with the rest of your PKI.
- Con: Renewal involves two teams on a schedule.
- Con: If the corporate CA team's OID/profile doesn't allow the name constraints IPA needs, you find out late.
Profiles, short version
A profile is a Dogtag template for "what fields are allowed/required on this kind of cert". IPA ships a few:
| Profile | Use for |
|---|---|
caIPAserviceCert | Standard service cert with SANs. 99% of what you'll issue. |
IECUserRoles | User certs used by Dogtag internally — don't issue from this. |
KDCs_PKINIT_Certs | KDC certs for PKINIT. |
Custom profiles are possible (ipa certprofile-import) when you need ExtKeyUsage combinations the default won't emit (e.g. TLS client + code signing). Treat them like CA change-management: version-controlled, reviewed, tested on a non-prod sub-CA first.
Common errors
| Error | Cause | Fix |
|---|---|---|
CA is not configured on a replica | Replica wasn't installed with --setup-ca. | ipa-ca-install on that replica — see promoting a replica. |
DRM is not installed / KRA is not configured | You tried to use vault / key-archival on a replica without KRA. | ipa-kra-install. |
could not find a suitable authorisation principal | The requester has no authority to ask IPA for this cert. | ipa service-add-host to grant the issuing host permission. |
invalid subject: missing nsNSCAVertificateAuthoritySubjectDN | Sub-CA creation races Dogtag. Retry after a few seconds. | Wait, then ipa ca-add again; restart pki-tomcatd@pki-tomcat if persistent. |
profile is not enabled | You're requesting against a disabled custom profile. | ipa certprofile-mod <name> --store=True --enabled=True. |
| Cert issued but reload step in certmonger failed | The -C command's exit code was non-zero. | Check journalctl -u certmonger; run the post-save command by hand to reproduce. |
| After CA renewal, clients distrust new certs | Old trust bundle is still on clients. | ipa-certupdate on clients; SSSD will pull the new bundle on next refresh. |
Can't connect to the CA on request | Dogtag down; firewall blocks loopback weirdly; ipa.socket issue. | systemctl status pki-tomcatd@pki-tomcat; journalctl -u pki-tomcatd@pki-tomcat. |
Verification
- [ ]
ipa-healthcheck --failures-onlyis clean on every CA replica - [ ]
getcert listlists every cert certmonger tracks, all in statusMONITORING - [ ] CA renewal date is > 12 months away, or a renewal event is scheduled
- [ ] At least two IPA servers have
--setup-ca - [ ] Sub-CA public certs are in
/etc/pki/ca-trust/source/anchors/on every consumer that needs them - [ ] ACME directory URL is in the standard internal runbook if you enabled it
- [ ]
ipa cert-show 1returns the CA cert — if it errors you have a bigger problem
See also: FreeIPA, FreeIPA Replication, Certificates, Kerberos Keytab Rotation.