linux_ejbca

Ceci est une ancienne révision du document !


EJBCA - Installation d'une infrastructure à clés publiques (PKI)

CréationNicolas THOREZ 2024/03/19 10:29

Une infrastructure à clés publiques ou PKI (Public Key Infrastructure) est un ensemble de services permettant de gérer des clés publiques et se faisant, permettant l'authentification d'un service, système ou utilisateur.

Réf : Wikipédia

Dans cette procédure, nous allons voir la mise en place d'une PKI via le logiciel EJBCA (Enterprise JavaBeans Certificate Authority) en version Community.

Droits

Cette procédure nécessite des droits root. La plus grande prudence est donc requise.

Réalisation

Cette procédure a été réalisée et testé sur un VM en Debian 11, hébergée sur un hyperviseur Proxmox 8.0.4.

Réf : EJBCA

  • On installe les paquets de prérequis :

apt install -y ca-certificates curl

  • On ajoute le dépôt de docker :

install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null

  • On installe les paquets nécessaires :

apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

  • On créé et on va dans l'arborescence du projet :

mkdir -p /opt/ejbca/containers/datadbdir
cd /opt/ejbca/containers/

  • On crée le fichier de configuration pour le docker :

nano docker-compose.yml

version: '3'
networks:
  access-bridge:
    driver: bridge
  application-bridge:
    driver: bridge
services:
  ejbca-database:
    container_name: ejbca-database
    image: "library/mariadb:latest"
    networks:
      - application-bridge
    environment:
      - MYSQL_ROOT_PASSWORD=foo123
      - MYSQL_DATABASE=ejbca
      - MYSQL_USER=ejbca
      - MYSQL_PASSWORD=ejbca
    volumes:
      - ./datadbdir:/var/lib/mysql:rw
  ejbca-node1:
    hostname: ejbca-node1
    container_name: ejbca
    image: keyfactor/ejbca-ce:latest
    depends_on:
      - ejbca-database
    networks:
      - access-bridge
      - application-bridge
    environment:
      - DATABASE_JDBC_URL=jdbc:mariadb://ejbca-database:3306/ejbca?characterEncoding=UTF-8
      - LOG_LEVEL_APP=INFO
      - LOG_LEVEL_SERVER=INFO
      - TLS_SETUP_ENABLED=simple
    ports:
      - "80:8080"
      - "443:8443"
  • On prendra soin de personnaliser MYSQL_ROOT_PASSWORD (le mot de passe pour la base de données de la PKI).
  • Une fois enregistré, on peut lancer la création du docker :

docker compose up -d

  • La commande suivante permet de voir l'état d'initialisation de l'instance. Une fois terminée, les logs affiche l'adresse pour la configuration via l'interface web :

docker compose logs -f

  • Retour console :
ejbca           | 2024-03-19 12:51:19,457+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) Waiting 5 seconds before signaling application readiness to ensure proper handling of PublicAccessAuthenticationToken.
ejbca           | 2024-03-19 12:51:24,471+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) Health check now reports application status at /ejbca/publicweb/healthcheck/ejbcahealth
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *****************************************************************************************
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *                                                                                       *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) * A fresh installation was detected and a ManagementCA was created for your initial     *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) * access to the system.                                                                 *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *                                                                                       *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *   URL:      https://ejbca-node1:443/ejbca/adminweb/                                   *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *                                                                                       *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) * If you use different port mapping or a proxy, please adapt the URL above accordingly. *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *                                                                                       *
ejbca           | 2024-03-19 12:51:24,484+0000 INFO  [/opt/keyfactor/bin/start.sh] (process:1) *****************************************************************************************

Pour gérer plus facilement l'état de l'instance (démarrage, redémarrage, arrêt, status), j'ai créé le script suivant :

touch /opt/ejbca/manage-ejbca-daemon.sh
chmod +x /opt/ejbca/manage-ejbca-daemon.sh
nano /opt/ejbca/manage-ejbca-daemon.sh

#!/bin/bash

##########################################
#                                        #
#   Script de gestion du service EJBCA   #
#                                        #
##########################################

#===========#
# Variables #
#===========#

# Dossier de travail
WRKDIR=/opt/ejbca/containers

# Nom de l'instance ebjca
EJBCA=ejbca

# Nom de l'instance ebjca-database
EJBDB=ejbca-database

#===========#
# Fonctions #
#===========#

# Demande d'aide
get-help() {
        echo "Script de gestion du service EJBCA"
        echo ""
        echo "Usage : ./manage-ejbca-daemon.sh [start|stop|restart|status|help]"
        echo ""
        echo "start                     Démarre l'instance."
        echo "stop                      Arrête l'instance."
        echo "restart                   Redémarre l'instance."
        echo "status                    Affiche l'état de l'instance."
        echo "help                      Affiche cette aide."
}

#=======================#
# Gestion des arguments #
#=======================#

case $1 in
        "start"|"restart"|"stop"|"status")
                ACTION="$1"
                ;;
        "help")
                get-help
                exit 0
                ;;
        *)
                echo "Erreur : Argument $1 inconnu"
                echo ""
                get-help
                exit 2
                ;;
esac

#============#
# Traitement #
#============#

EJBCA_STATUS=$(docker container inspect -f '{{.State.Running}}' $EJBCA 2>&1)
EJBDB_STATUS=$(docker container inspect -f '{{.State.Running}}' $EJBDB 2>&1)

if [ "$EJBCA_STATUS" == "true" -a "$EJBDB_STATUS" == "true" ]; then
        STATUS=0
elif [ "$EJBCA_STATUS" == "true" -a "$EJBDB_STATUS" != "true" ]; then
        STATUS=1
elif [ "$EJBCA_STATUS" != "true" -a "$EJBDB_STATUS" == "true" ]; then
        STATUS=2
else
        STATUS=3
fi

case $ACTION in
        "start")
                # Vérification de l'état et action
                case $STATUS in
                        0)
                                # Démarré
                                echo "Instance déjà démarré"
                                CODE=1
                                ;;
                        1|2)
                                # Partiel
                                echo "Redémarrage de l'instance"
                                cd $WRKDIR && docker compose restart
                                CODE=0
                                ;;
                        3)
                                # Arrêté
                                echo "Démarrage de l'instance"
                                cd $WRKDIR && docker compose up -d
                                CODE=0
                                ;;
                        *)
                                # Autre
                                echo "Erreur status : $STATUS"
                                CODE=3
                                ;;
                esac
                ;;
        "stop")
                # Vérification de l'état et action
                case $STATUS in
                        0|1|2)
                                # Démarré
                                echo "Arrêt de l'instance"
                                cd $WRKDIR && docker compose down
                                CODE=0
                                ;;
                        3)
                                # Arrêté
                                echo "Instance déjà à l'arrêt"
                                CODE=1
                                ;;
                        *)
                                # Autre
                                echo "Erreur status : $STATUS"
                                CODE=3
                                ;;
                esac
                ;;
        "restart")
                # Vérification de l'état et action
                case $STATUS in
                        0)
                                # Démarré
                                echo "Redémarrage de l'instance"
                                cd $WRKDIR && docker compose restart
                                CODE=0
                                ;;
                        1|2)
                                # Partiel
                                echo "Instance partiellement démarrée, redémarrage complet..."
                                cd $WRKDIR && docker compose down && docker compose up -d
                                CODE=1
                                ;;
                        3)
                                # Arrêt
                                echo "Instance à l'arrêt, démarrage..."
                                cd $WRKDIR && docker compose up -d
                                CODE=1
                                ;;
                        *)
                                # Autre
                                echo "Erreur status : $STATUS"
                                CODE=3
                                ;;
                esac
                ;;
        "status")
                # Vérification de l'état et action
                case $STATUS in
                        0)
                                # Démarré
                                echo "Autorité de certification et base de données actives"
                                CODE=0
                                ;;
                        1)
                                # Base de données à l'arrêt
                                echo "Autorité de certification active mais la base de données est à l'arrêt"
                                CODE=1
                                ;;
                        2)
                                # Authorité à l'arrêt
                                echo "Base de données active mais l'autorité de certification est à l'arrêt"
                                CODE=1
                                ;;
                        3)
                                # Arrêt
                                echo "Autorité de certification et base de données à l'arrêt"
                                CODE=2
                                ;;
                        *)
                                # Autre
                                echo "Erreur status : $STATUS"
                                CODE=3
                                ;;
                esac
                ;;
        *)
                # Autre
                echo "Erreur action : $ACTION"
                CODE=3
                ;;
esac

#========#
# Sortie #
#========#

exit $CODE

Pour que l'instance démarre automatiquement au démarrage de la VM, on édite alors la crontab de root :

crontab -e

Et on ajoute la ligne suivante :

@reboot         /opt/ejbca/manage-ejbca-daemon.sh start

Nomenclature

Du point de vue de EJBCA, tous les utilisateurs sont des administrateurs. Les comptes sont déterminés selon ces différents types :
  • SuperAdmin : Compte d'administration ayant tous les droits.
  • Admin : Compte d'administration avec des droits limités.

De mon côté, je pars toujours du fait qu'un administrateur a toujours tous les droits. Lorsque les droits sont limités, on est alors sur un profils d'utilisateur (User) ou d' utilisateur privilégié (PowerUser).

Du coup, dans la suite de cette procédure, j'utiliserais les termes suivant :

  • Administrateur (Admin) pour le rôle SuperAdmin de EJBCA
  • Utilisateur (User) ou Utilisateur privilégié (PowerUser)pour le rôle Admin de EJBCA

Création du certificat

  • Lors de la 1ère connexion à l'interface, il est possible que votre navigateur vous propose d'envoyer un certificat pour l'authentification. Il faudra décocher la case Se souvenir de cette décision et refuser cet envoi. Ce message peut revenir plusieurs fois tant que l'authentification n'est pas paramétrée :
  • Pour créer un compte admin, on ira dans RA Web :
  • Dans la nouvelle fenêtre, on ira dans la section Request new certificate et on cliquera sur Make New Request :
  • Dans la section Select Request Template, on choisit les options suivantes :
    • Certificate subtype : ENDUSER (default)
    • Key-pair generation : By the CA
  • Dans la section Select key algorithm, on choisira :
    • Key algorithm : RSA 2048 bits
  • Dans la section Provide request info, on entre les informations :
    • CN, Common Name : on entre le nom du compte administrateur.
    • Key Recoverable : on décoche le case.
  • Dans la section Provide User Credentials, on entre les informations :
    • Username : Le nom de du compte administrateur.
    • Enrollment code : Le mot de passe permettant d'enregistrer le certificat.
    • Confirm enrollment code : On confirme le mot de passe précédent.
    • Email : L'adresse mail associé à ce compte d'administration.
  • Finalement, dans la section Confirm request, on trouvera le résumé de nos paramétrages et on pourra télécharger le certificat en cliquant sur Download PKCS#12 :

Import du certificat dans le navigateur

Navigateur

J'utilise principalement Firefox en tant que navigateur internet. La procédure est donc basée sur ce dernier mais reste relativement similaire sur les autres navigateurs.
  • Maintenant, il faut importer le certificat dans le navigateur. Pour Firefox, on ira donc dans le menu Paramètres puis Vie privée et sécurité et enfin Afficher les certificats… :
  • Dans le gestionnaire de certificats, on sélectionne Vos certificats et on clique sur Importer… :
  • On choisit le certificat créé, on entre le mot de passe de l'enregistrement et on clique sur Connexion :
  • On peut vérifier la présence du nouveau certificat dans la liste et on sort du gestionnaire.

Création du compte sur EJBCA

  • On retourne sur l'interface d'administration de EJBCA et on clique sur Roles and Access Rules :
  • On supprime Public Access Role et on édite les membres de Super Administrator Role en cliquant sur Members :
  • On paramètre :
    • Match with : On sélectionne X509: CN, Common name.
    • CA : On choisit ManagementCA.
    • Match Value : On entre le nom du compte administrateur tel qu'il a été entré dans le champs CN, Common Name lors de la création du certificat. Attention, ce champs est sensible à la casse.
    • Description : Optionnel, cela permet d'identifier plus facilement le compte.
  • Une fois les paramètres réglés, on valide en cliquant sur Add :
  • On redémarre l'instance et on attend son démarrage complet :

/opt/ejbca/manage-ejbca-daemon.sh restart
cd /opt/ejbca/containers/ && docker compose logs -f | grep 'Health ckeck now reports application'

Test et validation

  • On ferme le navigateur pour vider le cache et on se reconnecte sur l'interface d'administration et lors de la demande d'envoi de certificat, on choisit le certificat créé.

Décisions d'authentification

Si à la reconnexion, vous n'avez pas de demande de certificat, c'est très probablement parce que Firefox a enregistré la décision de ne pas en envoyer. Pour réinitialiser cette décision, il suffit de supprimer l'entrée correspondante à l'adresse du serveur dans le gestionnaire de certificats de Firefox (ouvert lors de l'enregistrement du certificat), onglet Décisions d'authentification. Une fois la réinitialisation faîte, on peut retenter la connexion.
  • On retourne sur l'interface d'administration, dans Roles and Access Rules, et Members de Super Administrator Role.
  • On supprime PublicAccessAuthenticationToken :

Echec d'authentification

Si vous ne vous êtes pas connecté grâce au certificat, alors vous aurez une erreur et vous ne pourrez pas supprimer l'accès publique.

Opérationnel

A ce stade, vous avez une infrastructure opérationnelle. Félicitations.

On peut désormais créer des autorités de certifications : EJBCA - Création de certificats racine et intermédiaire

Entrer votre commentaire. La syntaxe wiki est autorisée:
 
  • linux_ejbca.1710935531.txt.gz
  • Dernière modification : 2024/03/20 12:52
  • de nekan