PKI : Installation de DogTag avec backend LDAP

De Adadov.net wiki
Ecrit Par : Adadov

Une bonne PKI n'est pas forcément utile pour tout le monde, la plupart du temps une installation avec les paramètres par défaut suffira. Vous trouverez pleins de documentations sur le net pour ces cas. Mais dans certains cas, il faut aller plus loin ... Que ce soit par challenge personnel ou besoin précis, les choses se corsent vite ... Documentations manquantes, petites erreurs et autres dysfonctionnement.

On peut vite passer des heures à s'arracher les cheveux.

Donc après avoir agravé mon état de stress, je documente ici mon travail afin de m'aider moi tout en essayant d'éviter le burnout à d'autres par la même occasion.

Backend LDAP sur 389 DS[modifier | modifier le wikicode]

Pour les LDAP, je ne vais pas m'étendre ici je ferais une documentation séparée.

Nous utilisons actuellement 3 LDAP 389 DS en réplication multi-maitres.

Après de nombreux tests avec des bases de données séparées et des sous-suffixe, je suis revenu au suffixe unique qui simplifie grandement le déploiement (et le redéploiment ...)

Fichier de déploiement LDAP[modifier | modifier le wikicode]

Voici le fichier de configuration des instances utilisé pour le stockage de notre PKI:
Fichier de déploiement du LDAP: ldap.cfg

Ce fichier est fait pour être modifié via sed avant son utilisation.

On trouve 4 balises à remplacer dans ce fichier:

  • ##NUM## : Le numéro du LDAP afin de pouvoir déployer facilement ldap01 ldap02 ldap03 ...
  • ##SUFFIX## : Le suffix principal ou basedn
  • ##PASSWD##: Le password du DirectoryManager
  • ##REPLPASSWD## : Le password du ReplicationManager

Déploiement de la PKI[modifier | modifier le wikicode]

J'ai choisi de limiter le déploiement initial aux services suivants:

  • CA: en même temps c'est le cœur du sujet
  • OCSP: Afin de fournir en live aux serveurs les statuts des certificats
  • KRA: Pour faciliter la gestion des clés

Ce petit ensemble m'a déjà pris plusieurs semaines de tests et recherches pour obtenir un résultat qui me convienne et qui fonctionne ... Vous verrez en bas quelques bugs rencontrés ...

Le certificat racine est externe, signé par une autre CA stockée hors ligne afin de la sécurisée.

Le certificat est importé automatiquement lors du déploiement, il se trouve dans le fichier pki-ecc.p12 avec sa chaine complète.

Description du fichier de déploiement[modifier | modifier le wikicode]

Variables personnalisées[modifier | modifier le wikicode]

 ldap_host = ldap.exemple.com
 ldap_port = 389
 secdomain_name = secdomain
 secdomain_user = secdomadmin
 basedn = dc=pki,dc=exemple.com
 pki_dns_domainname = exemple.com

Configuration des certificats[modifier | modifier le wikicode]

Pour chaque certificats on peut définir les paramètes suivant afin de les customiser comme on veut:

pki_ca_signing_nickname

Alias utilisé dans NSS DB

pki_ca_signing_key_size

Taille de la clé (pour une externe, elle doit aussi correspondre)

  • Pour RSA: 1024, 2048, 3072, 4096
  • Pour ECC: nitsp256, nitsp384, nitsp521
pki_ca_signing_key_type

Méthode chiffrement utilisée

rsa ou ecc

pki_ca_signing_key_algorithm

Type de signature utilisée pour la clé

pki_ca_signing_signing_algorithm

Encodage utilisée par la clé lorsqu'elle signe un certificat

pki_ca_signing_subject_dn

DN du certificat

Ce qui donne pour un certificat RSA:

pki_transport_nickname = pki_kra_transport
pki_transport_key_size = 2048
pki_transport_key_type = rsa
pki_transport_key_algorithm = SHA512withRSA
pki_transport_signing_algorithm = SHA512withRSA

Et pour un certificat ECC:

pki_audit_signing_nickname = pki_kra_audit_sign
pki_audit_signing_key_size = nistp521
pki_audit_signing_key_type = ecc
pki_audit_signing_key_algorithm = SHA512withEC
pki_audit_signing_signing_algorithm = SHA512withEC

Configuration de l'instance[modifier | modifier le wikicode]

 pki_hostname = pki.exemple.com
 pki_https_port = 8443
 pki_http_port = 8080
 pki_instance_name = pki-tomcat

Configuration des certificats à importer[modifier | modifier le wikicode]

 pki_import_system_certs = True
 pki_import_admin_cert = False

Configuration du compte administrateur[modifier | modifier le wikicode]

 pki_admin_uid = caadmin
 pki_admin_name = %(pki_admin_uid)s
 pki_admin_email = %(pki_admin_name)s@%(pki_dns_domainname)s
 pki_admin_nickname = %(pki_admin_uid)s
 pki_admin_subject_dn = cn = PKI Admin, o = %(pki_security_domain_name)s

Configuration du domaine de sécurité[modifier | modifier le wikicode]

 pki_security_domain_name = %(secdomain_name)s
 pki_security_domain_user = %(secdomain_user)s

Configuration du serveur LDAP[modifier | modifier le wikicode]

 pki_ds_hostname = %(ldap_host)s
 pki_ds_ldap_port = %(ldap_port)s
 pki_ds_secure_connection = False
 pki_ds_base_dn = dc=ca,%(basedn)s
 pki_ds_bind_dn = cn=directorymanager
 pki_ds_database = userroot
 pki_ds_create_new_db = False
 pki_ds_remove_data = True

Configuration du partage d'accès[modifier | modifier le wikicode]

 pki_share_db = True
 pki_share_dbuser_dn = uid=pkidbuser, ou=people, dc=ca, %(basedn)s

Configurations propres à la CA[modifier | modifier le wikicode]

 pki_existing = True
 pki_random_serial_numbers_enable = True
 pki_pkcs12_path = /root/pki-ecc.p12

Import du certificat racine[modifier | modifier le wikicode]

Comme dit précédemment, mon certificat racine vient d'une autre CA.

Il nous faut donc importer tout ça pour que notre déploiement se passe le mieux possible.

On initialise le stockage de certificats de notre utilisateur local, puis on importe la chaine de la CA dedans.

Attention, vous importerez aussi la clé privé de la CA, pensez à la supprimer ou réinitialiser votre stockage après l'installation !

[root@linux] # pki client init --forcedblclick to copy
[root@linux] # pki pkcs12 import --pkcs12 pki-ecc.p12 --password Secret.123

Installation de la CA[modifier | modifier le wikicode]

[root@linux] # pkispawn -f ca.cfg -s CA -vdblclick to copy

Installation de la KRA[modifier | modifier le wikicode]

[root@linux] # pkispawn -f ca.cfg -s KRA -vdblclick to copy

Installation d'OCSP[modifier | modifier le wikicode]

[root@linux] # pkispawn -f ca.cfg -s OCSP -vdblclick to copy

Installation d'ACME[modifier | modifier le wikicode]

Pour me simplifier l'installation j'ai préconfiguré les 4 fichiers ci-dessous et le script les envoie sur le serveur pendant le déploiement d'ACME.

Fichier database.conf[modifier | modifier le wikicode]

class=org.dogtagpki.acme.database.DSDatabase
url=ldap://ldap.exemple.com:389
authType=BasicAuth
bindDN=cn=directorymanager
bindPassword=
baseDN=dc=acme,dc=pki,dc=exemple,dc=com

Fichier realm.conf[modifier | modifier le wikicode]

class=org.dogtagpki.acme.realm.DSRealm
url=ldap://ldap.exemple.com:389
authType=BasicAuth
bindDN=cn=directorymanager
bindPassword=
usersDN=ou=people,dc=ca,dc=pki,dc=exemple,dc=com
groupsDN=ou=groups,dc=ca,dc=pki,dc=exemple,dc=com

Fichier issuer.conf[modifier | modifier le wikicode]

class=org.dogtagpki.acme.issuer.PKIIssuer
url=https://pki.exemple.com:8443
profile=acmeServerCert
username=
password=

Fichier metadata.conf[modifier | modifier le wikicode]

termsOfService=https://pki.exemple.com/acme/tos.pdf
website=https://pki.exemple.com
caaIdentities=exemple.com
externalAccountRequired=false

Script d'installation[modifier | modifier le wikicode]

Le script d'installation va mettre en place les fichiers préconfigurés et initialiser le LDAP avec les fichiers LDIF fournis.


Il nécessite d'avoir un fichier ~/.pwd/directorymanager contenant le mot de passe du directory manager.

#!/usr/bin/bash

DGHOST=pki.exemple.com
INSTANCE=pki-tomcat
LDAPHOST=ldap.exemple.com
LDAPPORT=389
BASEDN=dc=exemple,dc=com
SUFFIX=acme

ssh root@${DGHOST} pki-server acme-create -i ${INSTANCE}
scp *.conf root@${DGHOST}:/etc/pki/${INSTANCE}/acme/
cat <<"EOF" | ssh root@${DGHOST} 'bash'
cat /etc/pki/${INSTANCE}/acme/database/ds/schema.ldif    {{!}} ldapadd -H ldap://${LDAPHOST}:${LDAPPORT} -D cn=directorymanager -y ~/.pwd/directorymanager -c -x
cat /etc/pki/${INSTANCE}/acme/database/ds/create.ldif    {{!}} sed -e "s/dc=example,dc=com/${BASEDN}/" \
    -e 's/{instanceId}/${INSTANCE}/g' \
    -e "s/{database}/userroot/" \
    -e "s/{rootSuffix}/dc=${SUFFIX},dc=pki,${BASEDN}/" {{!}}ldapadd -H ldap://${LDAPHOST}:${LDAPPORT} -D cn=directorymanager -y ~/.pwd/directorymanager -c -x
cat /etc/pki/${INSTANCE}/acme/realm/ds/create.ldif       {{!}} sed -e "s/dc=example,dc=com/${BASEDN}/" \
    -e 's/{instanceId}/${INSTANCE}/g' \
    -e "s/{database}/userroot/" \
    -e "s/{rootSuffix}/dc=${SUFFIX},dc=pki,${BASEDN}/" {{!}}ldapadd -H ldap://${LDAPHOST}:${LDAPPORT} -D cn=directorymanager -y ~/.pwd/directorymanager -c -x
cat /etc/pki/${INSTANCE}/acme/database/ds/index.ldif     {{!}} sed -e "s/dc=example,dc=com/${BASEDN}/" \
    -e 's/{instanceId}/${INSTANCE}/g' \
    -e "s/{database}/userroot/" \
    -e "s/{rootSuffix}/dc=${SUFFIX},dc=pki,${BASEDN}/" {{!}}ldapadd -H ldap://${LDAPHOST}:${LDAPPORT} -D cn=directorymanager -y ~/.pwd/directorymanager -c -x
cat /etc/pki/${INSTANCE}/acme/database/ds/indextask.ldif {{!}} sed -e "s/dc=example,dc=com/${BASEDN}/" \
    -e 's/{instanceId}/${INSTANCE}/g' \
    -e "s/{database}/userroot/" \
    -e "s/{rootSuffix}/dc=${suffix},dc=pki,${BASEDN}/" {{!}}ldapadd -H ldap://${LDAPHOST}:${LDAPPORT} -D cn=directorymanager -y ~/.pwd/directorymanager -c -x
pki-server acme-deploy -i ${INSTANCE}
EOF

Fichier de déploiement de la PKI[modifier | modifier le wikicode]

J'ai pris le parti d'un fichier unique car j'ai écris un script de déploiement automatique pour m'éviter l'internement à force de réinstallation, mais vous pouvez tout aussi bien le séparer.

Le fichier complet est disponible ici: ca.cfg

Configuration de la CA[modifier | modifier le wikicode]

Création d'un compte administrateur supplémentaire[modifier | modifier le wikicode]

[root@linux] # pk12util -i .dogtag/dg-pki/ca_admin_cert.p12 -d .dogtag/nssdb/dblclick to copy
[root@linux] # alias pki='\pki -n caadmin'
[root@linux] # pki ca user add admin2 --fullName "Second Admin"
[root@linux] # pki kra user add admin2 --fullName "Second Admin"
[root@linux] # pki ocsp user add admin2 --fullName "Second Admin"
[root@linux] # pki ca group member add "Administrators" admin2
[root@linux] # pki ca group member add "Enterprise OCSP Administrators" admin2
[root@linux] # pki ca group member add "Enterprise KRA Administrators" admin2
[root@linux] # pki ca group member add "Enterprise CA Administrators" admin2
[root@linux] # pki ca group member add "Certificate Manager Agents" admin2
[root@linux] # pki ocsp group member add "Online Certificate Status Manager Agents" admin2
[root@linux] # pki kra group member add "Data Recovery Manager Agents" admin2

Ajout de profils supplémentaires[modifier | modifier le wikicode]

Pour ajouter un profil, il y a plusieurs informations à ajouter:

  • D'abord importer le fichier, le placer dans /etc/pki/pki-dogtag/ca/profiles/ca/
  • Déclarer le profil dans le fichier CS.cfg en ajoutant les lignes suivantes:
profile.[profilename].class_id=caEnrollImpl
profile.[profilename].config=/var/lib/pki/dogtag-pki/ca/profiles/ca/[profilename].cfg
  • Ajouter dans la liste située dans CS.cfg ce nouveau profil (la place dans la liste fait la place sur l'interface web
profile.list=[profilename],[...]

Plusieurs profils personnalisés sont disponibles ici

Publication des certificats dans LDAP[modifier | modifier le wikicode]

Voici les entrées modifiées dans /etc/pki/pki-dogtag/ca/CS.cfg pour activer la publication des certificats dans le LDAP.

Publication de la CRL au démarrage:

ca.crl.MasterCRL.publishOnStart=true

Cette option est obligatoire pour que la règle LdapCrlRule fonctionne:

ca.publish.createOwnDNEntry=true

Pour activer les règles il faut passer à true les variables de configurations suivantes:

ca.publish.rule.instance.LdapCaCertRule.enable=true
ca.publish.rule.instance.LdapCrlRule.enable=true
ca.publish.rule.instance.LdapUserCertRule.enable=true
ca.publish.rule.instance.LdapXCertRule.enable=true
ca.publish.rule.instance.ocsprule-[...]-8443.enable=true

Pour activer toutes les règles un petit coup de sed suffit

[root@linux] # sed -i -r 's/(ca\.publish\.rule\.instance\.[^.]*\.enable=)false/\1true/' /etc/pki/pki-dogtag/ca/CS.cfgdblclick to copy

Configuration de SCEP[modifier | modifier le wikicode]

Pour SCEP j'ai cherché pendant un bon moment pour le faire fonctionner (et je cherche encore a comprendre pourquoi il bug avec iLO ...)

Mais pour l'activer il suffit de modifier les options suivantes:

ca.scep.enable=true

Vous pouvez modifier les algorithms avec les options suivantes:

ca.scep.allowedEncryptionAlgorithms=DES3
ca.scep.allowedHashAlgorithms=SHA256,SHA512
ca.scep.encryptionAlgorithm=DES3
ca.scep.hashAlgorithm=SHA256
ca.scep.nonceSizeLimit=16

Puis il faut surtout corriger le bug voir SCEP: le listener qui ne fonctionne pas

Notifications par email[modifier | modifier le wikicode]

Configurer le serveur SMTP à utiliser dans ca/CS.cfg:

smtp.host=smtp.exemple.com
smtp.port=25

Installation de certmonger sur un client[modifier | modifier le wikicode]

Création d'un compte pour certmonger[modifier | modifier le wikicode]

Ce script créra automatiquement un utilisateur certmonger avec les droits nécessaires ainsi que son certificat.

#!/usr/bin/env bash

PASSWD=123456

pki ca user add certmonger --fullName "Certmonger Agent"
pki ca group member add "Certificate Manager Agents" certmonger

REQ=$(pki client-cert-request UID=certmonger --curve nitsp384 | grep 'Request ID:' | awk -F: '{print $2}')
SERIAL=$(pki ca-cert request approve ${REQ} --force | grep 'Certificate ID:' | awk -F: '{print $2}')

pki ca user cert add certmonger --serial ${SERIAL}
pki client-cert-import certmonger --serial ${SERIAL}
pki pkcs12-cert-import certmonger --pkcs12-file certmonger.p12 --pkcs12-password ${PASSWD}

Configuration de la CA dans certmonger[modifier | modifier le wikicode]

Là je vous mets directement mon script, il est assez simple mais très efficace.

Exemple: Requête de certificat[modifier | modifier le wikicode]

Requérir un certificat qui sera placé en deux fichiers (clé et certificat)

[root@linux] # getcert request -f certificate.cert -k certificate.key -D $(hostname) -D $(hostname -s) -c dogtag -I $(hostname -s)dblclick to copy

Requérir un certificat qui sera placé dans une DB NSS

[root@linux] # getcert request -c dogtag -d nssdb -n $(hostname -s) -p /etc/dirsrv/slapd-dogtag/pwdfile.txt -I $(hostname -s) -D $(hostname) -D $(hostname -s)dblclick to copy

Mise en place d'un proxy apache[modifier | modifier le wikicode]

Afin de sécuriser un peu plus notre PKI, on va empêcher les accès directs à la machine. Pour la partie web on va donc mettre en place un proxy Apache devant.

Il devra:

  • Transmettre l'authentification par certificats
  • Fournir une connexion sécurisée HTTPS
  • Communiquer de façon sécurisée avec la PKI

Donc pour répondre au mieux à tout ça:

  • On mettra en place l'identification par certificats directement sur le proxy qui transmettra à la PKI
  • On forcera la navigation HTTPS
  • Pour la communication entre le proxy et la PKI on utiilisera AJP avec un shared secret.

Fichier de configuration du vhost SSL[modifier | modifier le wikicode]

On va ajouter une exception pour permettre le fonctionnement de certbot:

  Alias     /.well-known/acme-challenge /var/www/acme/
  ProxyPass /.well-known/acme-challenge/ !

Ajout de l'authentification par certificats:

  SSLCACertificateFile cabundle.pem
  SSLVerifyClient optional
  SSLVerifyDepth 2
  SSLOptions +ExportCertData +StdEnvVars

Pour autoriser l'accès le certificat doit contenir un champs Organisation avec pour valeur OurOrganisation

  <Location />
   SSLRequire ( %{SSL_CLIENT_S_DN_O} eq "OurOrganisation" )
  </Location>

Le proxy AJP

  ProxyPass        / ajp://192.168.0.X:8009/ secret=sharedSecret
  ProxyPassReverse / ajp://192.168.0.X:8009/ secret=sharedSecret

Et on ferme tout !

</VirtualHost>

Configuration de Tomcat[modifier | modifier le wikicode]

Du côté de Tomcat pour la PKI la configuration sera très rapide.

Il faut modifier le fichier /etc/pki/dg-pki/server.xml

Décommenter le connecteur AJP:

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" address="pki.exemple.com" secret="sharedSecret" name="Connector1"/>

Et dans le fichier /etc/pki/dg-pki/ca/CS.cfg

Modifier les lignes suivantes pour ajouter le port:

proxy.securePort=8009
proxy.unsecurePort=

Profils de certificats personnalisés[modifier | modifier le wikicode]

J'ai créé ou modifié quelques profils pour répondre à mes besoins, je vous mets les versions RSA pour les intéressés.

caAgentServerCertAltName[modifier | modifier le wikicode]

Ce profil permet de créer via un agent un certificat qui reprendra le champs subjectAltNames de la requête.

caAgentDualCert[modifier | modifier le wikicode]

Pratiquement comme le précédent à ceci près qu'il est client ET serveur.

caUserCert[modifier | modifier le wikicode]

Dans ce certificat je n'ai fais que modifier la contrainte pour le sujet, afin d'autoriser que le champs UID ne soit pas forcément le premier

Bugs rencontrés[modifier | modifier le wikicode]

Useless login pour ACME[modifier | modifier le wikicode]

Vous aurez peut être constaté sur certaines versions que rien ne se passe quand on se connecte sur ACME ...

Non ce n'est pas juste une fonction inutile (mais presque quand même ...) c'est dû a une erreur dans le code source ...

Pour la corriger il suffit de lancer le sed ci-dessous et vous aurez enfin accès au menu "Configuration"

[root@linux] # sed -i 's/data.Roles.Role/data.Roles/' /usr/share/pki/acme/webapps/acme/js/pki-acme.jsdblclick to copy

KRA et le certificat perdu ...[modifier | modifier le wikicode]

Lors de l'installation de KRA, j'ai pu constater que le générateur server side ne fonctionnait pas ... En effet il nous dit que son certificat doit être importé dans la NSS DB de la CA .... Et pourtant, il y est ...

Après avoir cherché près de 2 jours et tout retourné, j'ai fini par trouver ...

Le nickname n'est pas mis dans la configuration de la CA ...

[root@linux] # echo "ca.connector.KRA.transportCertNickname=kra_transport" >> /var/lib/pki/pki-dogtag/ca/conf/CS.cfgdblclick to copy

SCEP: le listener qui ne fonctionne pas ...[modifier | modifier le wikicode]

Alors il m'a fallu des heures pour trouver comment le fixer, mais le fixer est au final très simple ...

C'est tout simplement une mauvaise entrée dans le fichier de configuration qui pose problème, ils ont laissé le nom d'une classe disparue ...

Il faut donc tout simplement modifier le fichier CS.cfg ... Enfin j'ai modifié tous les fichiers du serveurs afin de m'assurer qu'aucun ne garde l'ancienne info non fonctionnelle ...

[root@linux] # sed -i .fixScep 's/com.netscape.cms.servlet.cert.scep.ChallengePassword/org.mozilla.jss.netscape.security.x509.ChallengePassword/' $(find / -name CS.cfg)dblclick to copy