Distribution et Gestion des Certificats sur macOS
Distribuez et gérez efficacement les certificats de sécurité sur vos appareils MacFleet en utilisant des outils de ligne de commande automatisés. Ce tutoriel couvre le déploiement de certificats, la validation, la gestion de confiance et l'intégration CA d'entreprise.
Comprendre la Gestion des Certificats macOS
macOS utilise plusieurs magasins de certificats et politiques de confiance :
- Trousseau Système - Certificats de confiance à l'échelle du système
- Trousseau de Connexion - Certificats spécifiques à l'utilisateur
- Paramètres de Confiance - Politiques de confiance et règles de validation des certificats
- Autorité de Certificat - Certificats CA racine et intermédiaires
Distribution Basique de Certificats
Télécharger et Installer un Certificat
#!/bin/bash
# Installation basique de certificat depuis une URL
CERT_URL="https://votre-domaine.com/certificates/company-ca.crt"
CERT_NAME="company-ca.crt"
# Télécharger le certificat
curl -O "$CERT_URL"
# Ajouter au trousseau système avec confiance
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "/Users/$CERT_NAME"
echo "Certificat installé avec succès"
Installer un Certificat Local
#!/bin/bash
# Installer un certificat depuis un fichier local
CERT_PATH="/path/to/certificate.crt"
if [[ -f "$CERT_PATH" ]]; then
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$CERT_PATH"
echo "Certificat local installé avec succès"
else
echo "Fichier de certificat non trouvé : $CERT_PATH"
exit 1
fi
Script de Gestion de Certificats d'Entreprise
#!/bin/bash
# Distribution et Gestion de Certificats MacFleet
# Déployer, valider et gérer les certificats sur les appareils d'entreprise
# Configuration
LOG_FILE="/var/log/macfleet_certificates.log"
BACKUP_DIR="/var/backups/certificates"
CERT_STORE_DIR="/Library/Keychains"
TEMP_DIR="/tmp/macfleet_certs"
# Configuration des sources de certificats
declare -A CERTIFICATE_SOURCES=(
["company-root-ca"]="https://pki.company.com/certs/root-ca.crt"
["company-intermediate-ca"]="https://pki.company.com/certs/intermediate-ca.crt"
["company-ssl-ca"]="https://pki.company.com/certs/ssl-ca.crt"
)
# Fonction de journalisation
log_action() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Créer les répertoires nécessaires
setup_directories() {
for dir in "$BACKUP_DIR" "$TEMP_DIR"; do
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
log_action "Répertoire créé : $dir"
fi
done
}
# Valider le fichier certificat
validate_certificate() {
local cert_file="$1"
local cert_name="$2"
log_action "Validation du certificat : $cert_name"
# Vérifier si le fichier existe et est lisible
if [[ ! -f "$cert_file" || ! -r "$cert_file" ]]; then
log_action "ERREUR : Fichier de certificat non accessible : $cert_file"
return 1
fi
# Valider le format du certificat avec openssl
if ! openssl x509 -in "$cert_file" -text -noout >/dev/null 2>&1; then
log_action "ERREUR : Format de certificat invalide : $cert_name"
return 1
fi
# Extraire les informations du certificat
local subject
local issuer
local expiry
subject=$(openssl x509 -in "$cert_file" -subject -noout | sed 's/subject=//')
issuer=$(openssl x509 -in "$cert_file" -issuer -noout | sed 's/issuer=//')
expiry=$(openssl x509 -in "$cert_file" -enddate -noout | sed 's/notAfter=//')
log_action "Détails du Certificat :"
log_action " Sujet : $subject"
log_action " Émetteur : $issuer"
log_action " Expire : $expiry"
# Vérifier si le certificat est expiré
if ! openssl x509 -in "$cert_file" -checkend 0 >/dev/null 2>&1; then
log_action "ATTENTION : Le certificat est expiré : $cert_name"
return 2
fi
# Vérifier si le certificat expire dans 30 jours
if ! openssl x509 -in "$cert_file" -checkend 2592000 >/dev/null 2>&1; then
log_action "ATTENTION : Le certificat expire dans 30 jours : $cert_name"
fi
log_action "Validation du certificat réussie : $cert_name"
return 0
}
# Télécharger un certificat depuis une URL
download_certificate() {
local cert_name="$1"
local cert_url="$2"
local cert_file="$TEMP_DIR/$cert_name.crt"
log_action "Téléchargement du certificat : $cert_name depuis $cert_url"
# Télécharger avec validation
if curl -s -f -L --connect-timeout 30 --max-time 120 -o "$cert_file" "$cert_url"; then
log_action "Certificat téléchargé avec succès : $cert_name"
echo "$cert_file"
return 0
else
log_action "ERREUR : Échec du téléchargement du certificat : $cert_name"
return 1
fi
}
# Sauvegarder les certificats existants
backup_certificates() {
local backup_timestamp
backup_timestamp=$(date '+%Y%m%d_%H%M%S')
local backup_file="$BACKUP_DIR/keychain_backup_$backup_timestamp.tar.gz"
log_action "Création de la sauvegarde des certificats : $backup_file"
if tar -czf "$backup_file" -C /Library/Keychains . 2>/dev/null; then
log_action "Sauvegarde créée avec succès : $backup_file"
return 0
else
log_action "ERREUR : Échec de la création de la sauvegarde"
return 1
fi
}
# Installer un certificat dans le trousseau système
install_certificate() {
local cert_file="$1"
local cert_name="$2"
local trust_policy="${3:-trustRoot}"
log_action "Installation du certificat : $cert_name avec la politique de confiance : $trust_policy"
# Vérifier si le certificat existe déjà
if security find-certificate -c "$cert_name" /Library/Keychains/System.keychain >/dev/null 2>&1; then
log_action "Le certificat existe déjà dans le trousseau système : $cert_name"
# Optionnellement supprimer le certificat existant
read -p "Le certificat existe déjà. Remplacer ? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
remove_certificate "$cert_name"
else
return 0
fi
fi
# Installer le certificat
if sudo security add-trusted-cert -d -r "$trust_policy" -k /Library/Keychains/System.keychain "$cert_file"; then
log_action "Certificat installé avec succès : $cert_name"
# Vérifier l'installation
if security find-certificate -c "$cert_name" /Library/Keychains/System.keychain >/dev/null 2>&1; then
log_action "Vérification du certificat réussie : $cert_name"
return 0
else
log_action "ERREUR : Échec de la vérification du certificat : $cert_name"
return 1
fi
else
log_action "ERREUR : Échec de l'installation du certificat : $cert_name"
return 1
fi
}
# Supprimer un certificat du trousseau système
remove_certificate() {
local cert_name="$1"
log_action "Suppression du certificat : $cert_name"
if sudo security delete-certificate -c "$cert_name" /Library/Keychains/System.keychain 2>/dev/null; then
log_action "Certificat supprimé avec succès : $cert_name"
return 0
else
log_action "Certificat non trouvé ou suppression échouée : $cert_name"
return 1
fi
}
# Configurer la base de données d'autorisation
configure_authorization() {
log_action "Configuration de la base de données d'autorisation pour la gestion des certificats"
cat > "$TEMP_DIR/auth_config.plist" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>allow-root</key>
<true/>
<key>authenticate-user</key>
<true/>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>Vérifié par le framework Admin lors de modifications de certaines Préférences Système.</string>
<key>group</key>
<string>admin</string>
<key>session-owner</key>
<false/>
<key>shared</key>
<true/>
</dict>
</plist>
EOF
if sudo /usr/bin/security authorizationdb write system.preferences < "$TEMP_DIR/auth_config.plist"; then
log_action "Base de données d'autorisation configurée avec succès"
return 0
else
log_action "ERREUR : Échec de la configuration de la base de données d'autorisation"
return 1
fi
}
# Lister les certificats installés
list_certificates() {
log_action "Liste des certificats installés dans le trousseau système"
echo "=== Certificats du Trousseau Système ==="
security find-certificate -a -p /Library/Keychains/System.keychain | \
openssl x509 -text -noout | \
grep -E "(Subject:|Issuer:|Not After)" | \
sed 's/^[[:space:]]*//'
echo -e "\n=== Résumé des Certificats ==="
local cert_count
cert_count=$(security find-certificate -a /Library/Keychains/System.keychain | grep -c "keychain:")
echo "Total des certificats dans le trousseau système : $cert_count"
}
# Générer un rapport de certificats
generate_certificate_report() {
local report_file="$BACKUP_DIR/certificate_report_$(date '+%Y%m%d_%H%M%S').json"
log_action "Génération du rapport de certificats : $report_file"
{
echo "{"
echo " \"report_date\": \"$(date -Iseconds)\","
echo " \"hostname\": \"$(hostname)\","
echo " \"system_info\": {"
echo " \"os_version\": \"$(sw_vers -productVersion)\","
echo " \"build_version\": \"$(sw_vers -buildVersion)\""
echo " },"
echo " \"certificates\": ["
local first=true
while IFS= read -r cert_hash; do
if [[ "$first" == true ]]; then
first=false
else
echo ","
fi
local cert_info
cert_info=$(security find-certificate -a -Z /Library/Keychains/System.keychain | \
awk -v hash="$cert_hash" '
/^SHA-1 hash:/ { if ($3 == hash) found=1; next }
found && /^[[:space:]]*"/ { print; found=0 }')
echo " {"
echo " \"hash\": \"$cert_hash\","
echo " \"subject\": $cert_info"
echo -n " }"
done < <(security find-certificate -a -Z /Library/Keychains/System.keychain | \
grep "SHA-1 hash:" | awk '{print $3}')
echo ""
echo " ],"
echo " \"trust_settings\": $(security trust-settings-export -d /tmp/trust_settings.plist && plutil -convert json -o - /tmp/trust_settings.plist 2>/dev/null || echo 'null')"
echo "}"
} > "$report_file"
log_action "Rapport de certificats généré : $report_file"
echo "$report_file"
}
# Déployer plusieurs certificats
deploy_certificate_bundle() {
log_action "=== Début du déploiement du bundle de certificats ==="
local success_count=0
local total_count=0
local failed_certs=()
for cert_name in "${!CERTIFICATE_SOURCES[@]}"; do
total_count=$((total_count + 1))
local cert_url="${CERTIFICATE_SOURCES[$cert_name]}"
log_action "Traitement du certificat : $cert_name"
# Télécharger le certificat
local cert_file
if cert_file=$(download_certificate "$cert_name" "$cert_url"); then
# Valider le certificat
if validate_certificate "$cert_file" "$cert_name"; then
# Installer le certificat
if install_certificate "$cert_file" "$cert_name"; then
success_count=$((success_count + 1))
log_action "Certificat déployé avec succès : $cert_name"
else
failed_certs+=("$cert_name")
fi
else
failed_certs+=("$cert_name")
fi
# Nettoyer le fichier temporaire
rm -f "$cert_file"
else
failed_certs+=("$cert_name")
fi
done
log_action "=== Résumé du déploiement de certificats ==="
log_action "Total des certificats : $total_count"
log_action "Déployés avec succès : $success_count"
log_action "Déploiements échoués : ${#failed_certs[@]}"
if [[ ${#failed_certs[@]} -gt 0 ]]; then
log_action "Certificats échoués : ${failed_certs[*]}"
fi
return $((total_count - success_count))
}
# Fonction d'exécution principale
main() {
local action="${1:-deploy}"
log_action "=== Démarrage de la Gestion des Certificats MacFleet ==="
log_action "Action : $action"
log_action "Nom d'hôte : $(hostname)"
log_action "Utilisateur : $(whoami)"
# Configuration
setup_directories
case "$action" in
"deploy")
backup_certificates
configure_authorization
deploy_certificate_bundle
list_certificates
generate_certificate_report
;;
"list")
list_certificates
;;
"report")
generate_certificate_report
;;
"backup")
backup_certificates
;;
"remove")
if [[ -n "$2" ]]; then
remove_certificate "$2"
else
echo "Usage : $0 remove <nom_certificat>"
exit 1
fi
;;
*)
echo "Usage : $0 {deploy|list|report|backup|remove}"
echo " deploy - Déployer tous les certificats configurés"
echo " list - Lister les certificats installés"
echo " report - Générer un rapport de certificats"
echo " backup - Sauvegarder les certificats actuels"
echo " remove - Supprimer un certificat spécifique"
exit 1
;;
esac
# Nettoyage
rm -rf "$TEMP_DIR"
log_action "=== Gestion des certificats terminée ==="
}
# Exécuter la fonction principale
main "$@"
Politiques de Confiance des Certificats
macOS prend en charge différentes politiques de confiance pour les certificats :
Politique de Confiance | Description | Cas d'Usage |
---|---|---|
trustRoot | Certificat racine de confiance | Certificats CA racine |
trustAsRoot | Faire confiance comme racine sans contraintes d'usage | Certificats CA d'entreprise |
deny | Refuser explicitement la confiance | Certificats révoqués ou blacklistés |
unspecified | Utiliser la confiance par défaut du système | Laisser le système déterminer la confiance |
Validation et Sécurité des Certificats
Vérifier la Chaîne de Certificats
#!/bin/bash
# Vérifier la chaîne de certificats et la validation
verify_certificate_chain() {
local cert_file="$1"
local ca_bundle="/etc/ssl/cert.pem"
echo "Vérification de la chaîne de certificats..."
# Vérification basique du certificat
if openssl verify -CAfile "$ca_bundle" "$cert_file"; then
echo "✅ La chaîne de certificats est valide"
else
echo "❌ Échec de la vérification de la chaîne de certificats"
return 1
fi
# Vérifier les objectifs du certificat
echo "Objectifs du certificat :"
openssl x509 -in "$cert_file" -purpose -noout
# Extraire l'usage des clés
echo "Usage des clés :"
openssl x509 -in "$cert_file" -text -noout | grep -A 5 "X509v3 Key Usage"
return 0
}
Analyse de Sécurité des Certificats
#!/bin/bash
# Analyse de sécurité des certificats installés
security_scan_certificates() {
echo "=== Analyse de Sécurité des Certificats ==="
# Trouver les certificats faibles (signatures MD5 ou SHA1)
echo "Vérification des algorithmes de signature faibles..."
security find-certificate -a -p /Library/Keychains/System.keychain | \
while read -r cert_pem; do
if [[ "$cert_pem" =~ ^-----BEGIN ]]; then
local sig_algo
sig_algo=$(echo "$cert_pem" | openssl x509 -text -noout | grep "Signature Algorithm" | head -1)
if [[ "$sig_algo" =~ (md5|sha1) ]]; then
local subject
subject=$(echo "$cert_pem" | openssl x509 -subject -noout)
echo "⚠️ Signature faible trouvée : $subject - $sig_algo"
fi
fi
done
# Trouver les certificats expirants
echo -e "\nVérification des certificats expirants..."
security find-certificate -a -p /Library/Keychains/System.keychain | \
while read -r cert_pem; do
if [[ "$cert_pem" =~ ^-----BEGIN ]]; then
if ! echo "$cert_pem" | openssl x509 -checkend 2592000 >/dev/null 2>&1; then
local subject
local expiry
subject=$(echo "$cert_pem" | openssl x509 -subject -noout)
expiry=$(echo "$cert_pem" | openssl x509 -enddate -noout)
echo "⚠️ Certificat expirant : $subject - $expiry"
fi
fi
done
echo "Analyse de sécurité terminée"
}
Renouvellement Automatique de Certificats
#!/bin/bash
# Script de renouvellement automatique de certificats
setup_certificate_renewal() {
local renewal_script="/usr/local/bin/macfleet_cert_renewal.sh"
local launchd_plist="/Library/LaunchDaemons/com.macfleet.cert.renewal.plist"
# Créer le script de renouvellement
cat > "$renewal_script" << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/macfleet_cert_renewal.log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "$(date): Démarrage du renouvellement automatique de certificats"
# Ajoutez votre logique de renouvellement de certificats ici
# Cela pourrait inclure :
# - Vérifier les dates d'expiration des certificats
# - Télécharger de nouveaux certificats depuis votre PKI
# - Remplacer les certificats expirés
# - Envoyer des alertes pour les renouvellements à venir
echo "$(date): Renouvellement de certificats terminé"
EOF
chmod +x "$renewal_script"
# Créer le LaunchDaemon pour l'exécution programmée
cat > "$launchd_plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macfleet.cert.renewal</string>
<key>ProgramArguments</key>
<array>
<string>$renewal_script</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</array>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
EOF
# Charger le LaunchDaemon
sudo launchctl load "$launchd_plist"
echo "Automatisation du renouvellement de certificats configurée"
echo "Script : $renewal_script"
echo "Planification : Quotidien à 2h00"
}
Intégration d'Entreprise
Services de Certificats Active Directory
#!/bin/bash
# Intégration avec Microsoft ADCS
deploy_adcs_certificates() {
local adcs_server="$1"
local cert_template="$2"
echo "Déploiement des certificats depuis ADCS : $adcs_server"
# Demander un certificat depuis ADCS
# Cela utiliserait typiquement certreq ou des outils similaires
# L'implémentation dépend de votre configuration ADCS
echo "L'intégration ADCS nécessite une configuration supplémentaire"
echo "Veuillez consulter votre administrateur PKI"
}
SCEP (Simple Certificate Enrollment Protocol)
#!/bin/bash
# Inscription de certificat SCEP
enroll_scep_certificate() {
local scep_url="$1"
local challenge_password="$2"
echo "Inscription de certificat via SCEP : $scep_url"
# Générer une clé privée
openssl genrsa -out device.key 2048
# Créer une demande de certificat
openssl req -new -key device.key -out device.csr -subj "/CN=$(hostname)"
# Note : L'inscription SCEP nécessite des outils supplémentaires comme sscep
echo "L'inscription SCEP nécessite sscep ou des outils similaires"
echo "Veuillez installer le client SCEP approprié"
}
Meilleures Pratiques
🔐 Considérations de Sécurité
- Validez les certificats avant l'installation
- Utilisez des politiques de confiance fortes appropriées à l'objectif du certificat
- Surveillez les dates d'expiration des certificats régulièrement
- Implémentez l'épinglage de certificats pour les applications critiques
📋 Directives de Gestion
- Sauvegardez les certificats avant de faire des changements
- Documentez les objectifs et propriétaires des certificats
- Utilisez l'automatisation pour les déploiements à grande échelle
- Surveillez l'usage et la validité des certificats
🔍 Dépannage
- Vérifiez le format du certificat si l'installation échoue
- Vérifiez la connectivité réseau pour les téléchargements
- Examinez les politiques de confiance si les certificats ne sont pas approuvés
- Consultez les journaux système pour des informations d'erreur détaillées
Notes Importantes
- Privilèges administrateur requis pour les modifications du trousseau système
- Validation des certificats essentielle pour la conformité de sécurité
- Sauvegardez les certificats existants avant les opérations en lot
- Testez le déploiement de certificats sur un sous-ensemble d'appareils d'abord
- Surveillez l'expiration des certificats pour éviter les interruptions de service