4th December 2023
The FreeIPA server comes with an embedded CA authority provided by Dogtag. It is quite complex to configure, but it’s better than nothing. I only managed to deploy RSA certificates, but it’s good enough for a small environment like mine.

Note: I’m planning to migrate over to EJBCA but that turned out to be a time vampire. Actually, everything PKI related consumes aaaalloooot of time. One can build a career on just knowing PKI. However, I’m doing another attempt on that next year.
The CA certificate
Depending on how you installed the FreeIPA server, CA certificate should be installed from the start.
Creating system certificates
Creating machine certificate for enrolled hosts with automatic renewal
It is assumed that the host is already enrolled with the FreeIPA client. Otherwise, check my instructions on how to install the FreeIPA Client.
Step 0: On the server you want to enroll, perform a kinit login:
wl@sauna-nms:~$ kinit admin
Password for admin@BASTUKLUBBEN.ONLINE:
wl@sauna-nms:~$
Note: In this example i used the local admin user, but any admin user will do. To configure your user to perform administrative tasks, check out my instructions on how to configure FreeIPA user to have admin privileges.
Create host principals
Step 1: Create a Kerberos principal for the service that will use/own the certificate. Also add the IPA server to be allowed to issue certificates on behalf of this principal:
Note: these commands can be run on any server, but for sanity sake, all commands are run on the host requesting the certificate, unless anything else is mentioned.
wl@sauna-nms:~$ ipa service-add HTTP/sauna-nms.bastuklubben.online
----------------------------------------------------------------------
Added service "HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE"
----------------------------------------------------------------------
Principal name: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: sauna-nms.bastuklubben.online
wl@sauna-nms:~$ ipa service-add-host --host=sauna-ipa.bastuklubben.online HTTP/sauna-nms.bastuklubben.online
Principal name: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: sauna-nms.bastuklubben.online, sauna-ipa.bastuklubben.online
-------------------------
Number of members added 1
-------------------------
Note: Make sure the FQDN of the has a DNS entry (it should have since you enrolled it with the FreeIPA client).
Step 1,5: If you are planning to use multiple SAN names for the host, these has to be added as dummy hosts and the configured as kerberos principals:
wl@sauna-nms:~$ ipa host-add nms.bastuklubben.online
------------------------------------
Added host "nms.bastuklubben.online"
------------------------------------
Host name: nms.bastuklubben.online
Principal name: host/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: host/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Password: False
Keytab: False
Managed by: nms.bastuklubben.online
wl@sauna-nms:~$ ipa service-add HTTP/nms.bastuklubben.online
----------------------------------------------------------------
Added service "HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE"
----------------------------------------------------------------
Principal name: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: nms.bastuklubben.online
NSS Configuration
Step 2: Create NSS certificate database which will hold the certificate. These commands are best run as root:
wl@sauna-nms:~$ sudo su
root@sauna-nms:/home/wl# mkdir -p /etc/httpd/nssdb; cd /etc/httpd/nssdb
root@sauna-nms:/etc/httpd/nssdb# certutil -N -d .
Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.
Enter new password:
Re-enter password:
Step 3: Create a password file to store the password
# nano /etc/httpd/nssdb/pwdfile.txt
Step 4: Set correct directory ownership and SELinux context
# chown :apache \*.db && chmod g+rw \*.db
# semanage fcontext -a -t cert_t "/etc/httpd/nssdb(/.\*)?"
# restorecon -FvvR /etc/httpd/nssdb/
Relabeled /etc/httpd/nssdb from unconfined_u:object_r:httpd_config_t:s0 to system_u:object_r:cert_t:s0
Relabeled /etc/httpd/nssdb/pkcs11.txt from unconfined_u:object_r:httpd_config_t:s0 to system_u:object_r:cert_t:s0
Relabeled /etc/httpd/nssdb/cert9.db from unconfined_u:object_r:httpd_config_t:s0 to system_u:object_r:cert_t:s0
Relabeled /etc/httpd/nssdb/key4.db from unconfined_u:object_r:httpd_config_t:s0 to system_u:object_r:cert_t:s0
Relabeled /etc/httpd/nssdb/pwdfile.txt from unconfined_u:object_r:cert_t:s0 to system_u:object_r:cert_t:s0
Note: this step may not be necessary for every linux platform.
Adding the CA certificate
Step 5: Add FreeIPA CA certificate:
# certutil -A -d . -n 'BASTUKLUBBEN.ONLINE IPA CA' -t CT,, -a \< /etc/ipa/ca.crt
Enter Password or Pin for "NSS Certificate DB":
Note: The CA certificate should be available in /etc/ipa/ca.crt if you enrolled it with the FreeIPA client.
Request a certificate from the FreeIPA CA
Step 6: Create a CSR request:
root@sauna-nms:/etc/httpd/nssdb# ipa-getcert request \
-d /etc/httpd/nssdb \
-n SAUNA-NMS \
-K HTTP/sauna-nms.bastuklubben.online \
-N CN=sauna-nms.bastuklubben.online,O=BASTUKLUBBEN.ONLINE \
-D nms.bastuklubben.online -g 2048 \
-p /etc/httpd/nssdb/pwdfile.txt
Explanations:
-d = database directory
-n = friendly name
-K = kerberos principal
-N = distinguished name
-D = SAN names
-g = RSA key size
-p = password file
Verification
Step 7: Check the status of the requested certificate. If request succeeded, it will be in a MONITORING state:
# ipa-getcert list -d /etc/httpd/nssdb/ -n SAUNA-NMS
Number of certificates and requests being tracked: 10.
Request ID '20230621181309':
status: MONITORING
stuck: no
key pair storage: type=NSSDB,location='/etc/httpd/nssdb',nickname='SAUNA-NMS',token='NSS Certificate DB',pinfile='/etc/httpd/nssd
b/pwdfile.txt'
certificate: type=NSSDB,location='/etc/httpd/nssdb',nickname='SAUNA-NMS',token='NSS Certificate DB'
CA: IPA
issuer: CN=Certificate Authority,O=BASTUKLUBBEN.ONLINE
subject: CN=sauna-nms.bastuklubben.online,O=BASTUKLUBBEN.ONLINE
issued: 2023-06-22 15:29:16 CEST
expires: 2025-06-22 15:29:16 CEST
dns: nms.bastuklubben.online,sauna-nms.bastuklubben.online
principal name: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
eku: id-kp-serverAuth,id-kp-clientAuth
pre-save command:
post-save command:
Step 8: Optionally show and validate the certificate
# certutil -V -u V -d . -n SAUNA-NMS
certutil: certificate is valid
# certutil -L -d . -n SAUNA-NMS
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 12 (0xc)
Signature Algorithm: PKCS \#1 SHA-256 With RSA Encryption
Issuer: "CN=Certificate Authority,O=BASTUKLUBBEN.ONLINE"
Validity:
Not Before: Thu Jun 22 13:29:16 2023
Not After : Sun Jun 22 13:29:16 2025
Subject: "CN=sauna-nms.bastuklubben.online,O=BASTUKLUBBEN.ONLINE"
Subject Public Key Info:
Public Key Algorithm: PKCS \#1 RSA Encryption
RSA Public Key:
Modulus:
< Output omitted >
The certificates and keys are stored inside the /etc/httpd/nssdb
directory:
root@sauna-nms:/etc/httpd/nssdb# ls
cert9.db key4.db pkcs11.txt pwdfile.txt
Export the Certificate and private key
You probably want a way to export the certificate and private key from the database so you can actually use it for something.
Notes:
you need to be root user to perform these commands
In this example I’m using the FreeIPA server
Export only certificate:
[wl@sauna-ipa /]$ cd /etc/httpd/nssdb/
[wl@sauna-ipa nssdb]$ sudo su
[root@sauna-ipa nssdb]#certutil -L -d . -a -n SAUNA-NMS > SAUNA-NMS.pem
Note: you can also download the certificate from the FreeIPA GUI. Just go to Authentication > Certificates.
Export certificate chain and private key:
[root@sauna-ipa nssdb]#pk12util -o SAUNA-NMS.p12 -n SAUNA-NMS -d .
Enter Password or Pin for "NSS Certificate DB":
Enter password for PKCS12 file:
Re-enter password:
pk12util: PKCS12 EXPORT SUCCESSFUL
[root@sauna-ipa nssdb]# ls
cert9.db key4.db pkcs11.txt pwdfile.txt SAUNA-NMS.p12
Convert to .pem format:
[root@sauna-ipa nssdb]# openssl pkcs12 -in SAUNA-NMS.p12 -out SAUNA-NMS-withkey.pem -nodes
Enter Import Password:
[root@sauna-ipa nssdb]# ls
cert9.db key4.db pkcs11.txt pwdfile.txt SAUNA-NMS.p12 SAUNA-NMS.pem
[root@sauna-ipa nssdb]# cat SAUNA-NMS-withkey.pem
Bag Attributes
friendlyName: SAUNA-NMS
localKeyID: C3 E8 54 96 10 38 EB 17 26 09 3E DD F7 79 95 86 FB F7 E0 BC
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDUMwzAuCtPQpdi
aAtaSkst/cZADvPmnKTC0AQ2du2orbxqquUYY216RHXxmTdRu9eFF9Cff2GO2SqT
24Wb51Q3GD5OECc9IA4yQGn6T+Psw0jjUJHB9qOn+Wp8H6nxxXRg2Ux1AtUck4kG
...<output omitted>
-----END PRIVATE KEY-----
Bag Attributes
friendlyName: BASTUKLUBBEN.ONLINE IPA CA
subject=O = BASTUKLUBBEN.ONLINE, CN = Certificate Authority
issuer=O = BASTUKLUBBEN.ONLINE, CN = Certificate Authority
-----BEGIN CERTIFICATE-----
MIIEozCCAwugAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MRwwGgYDVQQKDBNCQVNU
VUtMVUJCRU4uT05MSU5FMR4wHAYDVQQDDBVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
HhcNMjMwNTE4MTQ0NzA0WhcNNDMwNTE4MTQ0NzA0WjA+MRwwGgYDVQQKDBNCQVNU
VUtMVUJCRU4uT05MSU5FMR4wHAYDVQQDDBVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
...<output omitted>
-----END CERTIFICATE-----
Bag Attributes
friendlyName: SAUNA-NMS
localKeyID: C3 E8 54 96 10 38 EB 17 26 09 3E DD F7 79 95 86 FB F7 E0 BC
subject=O = BASTUKLUBBEN.ONLINE, CN = sauna-nms.bastuklubben.online
issuer=O = BASTUKLUBBEN.ONLINE, CN = Certificate Authority
-----BEGIN CERTIFICATE-----
MIIFoDCCBAigAwIBAgIBDTANBgkqhkiG9w0BAQsFADA+MRwwGgYDVQQKDBNCQVNU
VUtMVUJCRU4uT05MSU5FMR4wHAYDVQQDDBVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
HhcNMjMwNzA0MTczOTI0WhcNMjUwNzA0MTczOTI0WjBGMRwwGgYDVQQKDBNCQVNU
VUtMVUJCRU4uT05MSU5FMSYwJAYDVQQDDB1zYXVuYS1wdWIuYmFzdHVrbHViYmVu
Lm9ubGluZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQzDMC4K09C
l2JoC1pKSy39xkAO8+acpMLQBDZ27aitvGqq5RhjbXpEdfGZN1G714UX0J9/YY7Z
...<output omitted>
Extract the private key from SAUNA-NMS-withkey.pem:
[root@sauna-ipa nssdb]# openssl rsa -in SAUNA-NMS-withkey.pem -out SAUNA-NMS.key
writing RSA key
[root@sauna-ipa nssdb]# ls
cert9.db key4.db pkcs11.txt pwdfile.txt SAUNA-NMS.key SAUNA-NMS.p12 SAUNA-NMS-withkey.pem
[root@sauna-ipa nssdb]# cat SAUNA-NMS.key
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDUMwzAuCtPQpdi
aAtaSkst/cZADvPmnKTC0AQ2du2orbxqquUYY216RHXxmTdRu9eFF9Cff2GO2SqT
24Wb51Q3GD5OECc9IA4yQGn6T+Psw0jjUJHB9qOn+Wp8H6nxxXRg2Ux1AtUck4kG
ZjP9tnzm0Z/RX2OhTc52PEKZHbcd3rthW67Ht91SEiW0Cw4ggEyPWcCpQo53wrhu
hVECYzESDqDsGrNbMW2RF4SsovpmASqkiEfqC4tmBakLtN2QxwGQU2o11pfiJVlV
...<output omitted>
Creating a webserver certificate for unenrolled hosts
This method can be used for hosts that are not enrolled Linux hosts. For example, my TrueNAS server is running FreeBSD and i haven’t found a way to enroll it with the FreeIPA client. This method is much easier, but don’t have automatic renewal.
Note: these commands are run on the FreeIPA server in this example, but could be run on any enrolled host.
Step 1: Add host:
[ipa@sauna-ipa ~]$ kinit wl
[ipa@sauna-ipa ~]$ ipa host-add nextcloud.bastuklubben.online
[ipa@sauna-ipa ~]$ ipa service-add HTTP/nextcloud.bastuklubben.online
[ipa@sauna-ipa ~]$ ipa service-add-host --host=sauna-ipa.bastuklubben.online HTTP/nextcloud.bastuklubben.online
Step 2: Create a certificate request using OpenSSL
Step 3: Create the certificate by running this command inside the folder with the CSR file:
[ipa@sauna-ipa csr]$ ipa cert-request \
--principal=HTTP/nextcloud.bastuklubben.online --add nextcloud.csr
Afterwards you can download the certificate from the GUI under Authentication > Certificates.
Certificate Management
Here are some helpful commands if you misconfigured anything.
Delete service
Delete service if misconfigured:
$ ipa service-del HTTP/'sauna-nms.bastuklubben.online'
------------------------------------------------------------------------
Deleted service "HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE"
------------------------------------------------------------------------
Resubmit request
Resubmit request if it failed:
$ ipa-getcert resubmit \
-d /etc/httpd/nssdb \
-n Server-Cert \
-K HTTP/sauna-nms.bastuklubben.online \
-N CN=sauna-nms.bastuklubben.online,O=BASTUKLUBBEN.ONLINE \
-D nms.bastuklubben.online \
-g 2048 \
-p /etc/httpd/nssdb/pwdfile.txt
Resubmitting "20230621181309" to "IPA".
or:
ipa-getcert resubmit -i 20230621181309
Revoke certificate
$ ipa-getcert stop-tracking -i 20230621181309
$ ipa cert-revoke 12 ←
Serial Number
Note: to get the serial number: certutil -L -d . -n SAUNA-NMS
Certificate Troubleshooting for enrolled hosts
When creating certificates for the first time, there are many pitfalls. I will cover my experience here:
Problem 3007: ‘fqdn’ is required
[root@sauna-ipa nssdb]# ipa-getcert list -d /etc/httpd/nssdb/ -n Server-Cert
Number of certificates and requests being tracked: 10.
Request ID '20230621181309':
status: CA_REJECTED
ca-error: Server at https://sauna-ipa.bastuklubben.online/ipa/json denied our request, giving up: 3007 ('fqdn' is required).
stuck: yes
key pair storage: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert',token='NSS Certificate DB',pinfile='/etc/httpd/nssd
b/pwdfile.txt'
certificate: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert'
CA: IPA
issuer:
subject:
issued: unknown
expires: unknown
pre-save command:
post-save command:
track: yes
auto-renew: yes
Solution: Remove any single quotes ('') from the certificate request command
Problem 2100: Insufficient access
[root@sauna-ipa nssdb]# ipa-getcert list -d /etc/httpd/nssdb/ -n Server-Cert
Number of certificates and requests being tracked: 10.
Request ID '20230621181309':
status: CA_REJECTED
ca-error: Server at https://sauna-ipa.bastuklubben.online/ipa/json denied our request, giving up: 2100 (Insufficient access: Insufficient 'write' privilege to the 'userCertificate' attribute of entry 'krbprincipalname=HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE,cn=services,cn=accounts,dc=bastuklubben,dc=online'.).
stuck: yes
key pair storage: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert',token='NSS Certificate DB',pinfile='/etc/httpd/nssdb/pwdfile.txt'
certificate: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert'
CA: IPA
issuer:
subject:
issued: unknown
expires: unknown
pre-save command:
post-save command:ipa-getcert list -d /etc/httpd/nssdb/ -n Server-Cert auto-renew: yes
Solution: The documentation have very poorly explained what hostnames goes where. In this example I’m trying to issue a certificate from the IPA server. The problem is that the IPA server is not allowed to issue certificates for that principal. Make sure you configured Step 1 correctly.
You can add the IPA server (or any server) to be allowed to issue certificates:
$ ipa service-add-host --host=sauna-ipa.bastuklubben.online HTTP/sauna-nms.bastuklubben.online
Principal name: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/sauna-nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: sauna-nms.bastuklubben.online, sauna-ipa.bastuklubben.online
## Number of members added 1
Problem 4001: alt name in certificate does not exist
[root@sauna-ipa nssdb]# ipa-getcert list -d /etc/httpd/nssdb/ -n Server-Cert
Number of certificates and requests being tracked: 10.
Request ID '20230621181309':
status: CA_UNREACHABLE
ca-error: Server at https://sauna-ipa.bastuklubben.online/ipa/json failed request, will retry: 4001 (The service principal for subject alt name nms.bastuklubben.online in certificate request does not exist).
stuck: no
key pair storage: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert',token='NSS Certificate DB',pinfile='/etc/httpd/nssd
b/pwdfile.txt'
certificate: type=NSSDB,location='/etc/httpd/nssdb',nickname='Server-Cert'
CA: IPA
issuer:
subject:
issued: unknown
expires: unknown
pre-save command:
post-save command:
track: yes
auto-renew: yes
Solution: You need to manually create dummy-hosts with the SAN name:
[root@sauna-ipa nssdb]# ipa host-add nms.bastuklubben.online
Added host "nms.bastuklubben.online"
Host name: nms.bastuklubben.online
Principal name: host/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: host/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Password: False
Keytab: False
Managed by: nms.bastuklubben.online
Then add the service:
[root@sauna-ipa nssdb]# ipa service-add HTTP/nms.bastuklubben.online
Added service "HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE"
Principal name: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: nms.bastuklubben.online
[root@sauna-ipa nssdb]# ipa service-add-host --host sauna-ipa.bastuklubben.online HTTP/nms.bastuklubben.online
Principal name: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Principal alias: HTTP/nms.bastuklubben.online@BASTUKLUBBEN.ONLINE
Managed by: nms.bastuklubben.online, sauna-ipa.bastuklubben.online
## Number of members added 1
Problem: NEED_KEY_PAIR
[root@sauna-ipa /]# ipa-getcert list -d /etc/httpd/nssdb/ -n SAUNA-PUB
Number of certificates and requests being tracked: 11.
Request ID '20230704152545':
status: NEED_KEY_PAIR
stuck: no
key pair storage: type=NSSDB,location='/etc/httpd/nssdb',nickname='SAUNA-PUB',pinfile='/etc/httpd/nssdb/pwdfile.txt'
certificate: type=NSSDB,location='/etc/httpd/nssdb',nickname='SAUNA-PUB'
CA: IPA
issuer:
subject:
issued: unknown
expires: unknown
pre-save command:
post-save command:
track: yes
auto-renew: yes
Solution:
# systemctl stop certmonger
# systemctl start certmonger