Guide

Nouvelles mises à jour et améliorations de Macfleet.

Gestion Entreprise de Création Utilisateur sur macOS

Créez et provisionnez efficacement les comptes utilisateur dans votre déploiement MacFleet avec une gestion du cycle de vie utilisateur de niveau entreprise, des workflows automatisés et des contrôles de sécurité complets. Ce tutoriel transforme les commandes dscl et sysadminctl de base en solutions robustes de provisioning utilisateur.

Comprendre la Gestion de Création Utilisateur en Entreprise

La création utilisateur en entreprise nécessite plus qu'un simple provisioning de comptes, exigeant :

  • Workflows de provisioning automatisés avec configuration basée sur des modèles
  • Création de comptes axée sécurité avec attribution appropriée des privilèges
  • Intégration standardisée d'utilisateurs avec structures d'annuaire cohérentes
  • Capacités d'intégration avec les systèmes d'identité d'entreprise
  • Journalisation d'audit pour la surveillance de conformité et sécurité
  • Opérations utilisateur en masse pour une gestion de flotte efficace

Opérations de Création Utilisateur de Base

Commandes de Création Utilisateur Basiques

# Création utilisateur basée sur dscl
sudo dscl . -create /Users/Username
sudo dscl . -create /Users/Username RealName "John Doe"
sudo dscl . -passwd /Users/Username password_here
sudo dscl . -create /Users/Username UniqueID 1088
sudo dscl . -create /Users/Username PrimaryGroupID 20
sudo dscl . -create /Users/Username UserShell /bin/bash
sudo dscl . -create /Users/Username NFSHomeDirectory /Users/Username

# Création utilisateur basée sur sysadminctl
sysadminctl -addUser <username> -password <password>

Celles-ci utilisent l'utilitaire en ligne de commande du service d'annuaire (dscl) et le contrôle administrateur système (sysadminctl) pour la gestion des comptes utilisateur.

Système de Gestion de Création Utilisateur Entreprise

#!/bin/bash

# Système de Gestion de Création Utilisateur Entreprise MacFleet
# Provisioning utilisateur complet avec contrôles entreprise et automatisation

# Configuration
SCRIPT_NAME="Gestionnaire de Création Utilisateur MacFleet"
VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_user_creation.log"
AUDIT_LOG="/var/log/macfleet_user_audit.log"
TEMPLATES_DIR="/etc/macfleet/user_templates"
PROVISIONING_DIR="/var/lib/macfleet/provisioning"
TEMP_DIR="/tmp/macfleet_users"
MIN_UID=1000
MAX_UID=65000
DEFAULT_SHELL="/bin/zsh"
HOME_BASE_DIR="/Users"
COMPANY_DOMAIN="company.local"
REQUIRE_SECURE_PASSWORDS=true
ENFORCE_NAMING_CONVENTION=true
AUTO_FILEVAULT_ENABLE=true
STANDARD_GROUPS=("staff" "_appserverusr" "_appserveradm")
ADMIN_GROUPS=("admin" "staff" "_developer")
DEVELOPER_GROUPS=("staff" "_developer" "_appserverusr")

# Créer les répertoires nécessaires
mkdir -p "$TEMPLATES_DIR"
mkdir -p "$PROVISIONING_DIR"
mkdir -p "$TEMP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$(dirname "$AUDIT_LOG")"

# Définir les permissions sécurisées
chmod 700 "$TEMP_DIR"
chmod 750 "$PROVISIONING_DIR"
chmod 755 "$TEMPLATES_DIR"

# Fonctions de journalisation
log_operation() {
    local level="$1"
    local message="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local admin_user=$(whoami)
    echo "[$timestamp] [$level] [$admin_user] $message" | tee -a "$LOG_FILE"
}

log_audit_action() {
    local action_type="$1"
    local target_user="$2"
    local performed_by="$3"
    local details="$4"
    
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local source_ip=$(who am i | awk '{print $5}' | tr -d '()')
    echo "ACTION|$timestamp|$action_type|$target_user|$performed_by|$source_ip|$details" >> "$AUDIT_LOG"
}

# Générer un mot de passe sécurisé aléatoire
generate_secure_password() {
    local length="${1:-12}"
    local complexity="${2:-high}"
    
    case "$complexity" in
        "high")
            # Haute complexité : majuscules, minuscules, chiffres, symboles
            openssl rand -base64 32 | tr -d "=+/" | cut -c1-${length}
            ;;
        "medium")
            # Complexité moyenne : majuscules, minuscules, chiffres
            LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c ${length}
            ;;
        "basic")
            # Complexité basique : minuscules et chiffres
            LC_ALL=C tr -dc 'a-z0-9' </dev/urandom | head -c ${length}
            ;;
        *)
            echo "Erreur : Niveau de complexité inconnu"
            return 1
            ;;
    esac
}

# Valider la politique de mot de passe
validate_password() {
    local password="$1"
    local min_length=8
    local errors=()
    
    # Vérifier la longueur minimale
    if [[ ${#password} -lt $min_length ]]; then
        errors+=("Le mot de passe doit contenir au moins $min_length caractères")
    fi
    
    # Vérifier la lettre majuscule
    if [[ ! "$password" =~ [A-Z] ]]; then
        errors+=("Le mot de passe doit contenir au moins une lettre majuscule")
    fi
    
    # Vérifier la lettre minuscule
    if [[ ! "$password" =~ [a-z] ]]; then
        errors+=("Le mot de passe doit contenir au moins une lettre minuscule")
    fi
    
    # Vérifier le chiffre
    if [[ ! "$password" =~ [0-9] ]]; then
        errors+=("Le mot de passe doit contenir au moins un chiffre")
    fi
    
    # Vérifier le caractère spécial
    if [[ ! "$password" =~ [^A-Za-z0-9] ]]; then
        errors+=("Le mot de passe doit contenir au moins un caractère spécial")
    fi
    
    if [[ ${#errors[@]} -gt 0 ]]; then
        echo "Validation du mot de passe échouée :"
        printf '  - %s\n' "${errors[@]}"
        return 1
    fi
    
    return 0
}

# Valider le nom d'utilisateur selon la convention de nommage entreprise
validate_username() {
    local username="$1"
    local errors=()
    
    # Vérifier la longueur (3-20 caractères)
    if [[ ${#username} -lt 3 || ${#username} -gt 20 ]]; then
        errors+=("Le nom d'utilisateur doit contenir 3-20 caractères")
    fi
    
    # Vérifier les caractères valides (alphanumériques, points, tirets, underscores)
    if [[ ! "$username" =~ ^[a-zA-Z0-9._-]+$ ]]; then
        errors+=("Le nom d'utilisateur ne peut contenir que des lettres, chiffres, points, tirets et underscores")
    fi
    
    # Vérifier qu'il commence par une lettre
    if [[ ! "$username" =~ ^[a-zA-Z] ]]; then
        errors+=("Le nom d'utilisateur doit commencer par une lettre")
    fi
    
    # Vérifier les noms réservés
    local reserved_names=("admin" "root" "daemon" "nobody" "wheel" "operator" "system")
    for reserved in "${reserved_names[@]}"; do
        if [[ "$username" == "$reserved" ]]; then
            errors+=("Le nom d'utilisateur '$username' est réservé")
        fi
    done
    
    # Vérifier si le nom d'utilisateur existe déjà
    if dscl . -read "/Users/$username" &>/dev/null; then
        errors+=("Le nom d'utilisateur '$username' existe déjà")
    fi
    
    if [[ ${#errors[@]} -gt 0 ]]; then
        echo "Validation du nom d'utilisateur échouée :"
        printf '  - %s\n' "${errors[@]}"
        return 1
    fi
    
    return 0
}

# Trouver le prochain UID disponible
find_next_uid() {
    local start_uid="${1:-$MIN_UID}"
    local max_uid="${2:-$MAX_UID}"
    
    # Obtenir tous les UIDs existants
    local existing_uids=($(dscl . list /Users UniqueID | awk '{print $2}' | sort -n))
    
    # Trouver le premier UID disponible
    for ((uid=start_uid; uid<=max_uid; uid++)); do
        local uid_exists=false
        for existing_uid in "${existing_uids[@]}"; do
            if [[ $uid -eq $existing_uid ]]; then
                uid_exists=true
                break
            fi
        done
        
        if [[ "$uid_exists" == "false" ]]; then
            echo "$uid"
            return 0
        fi
    done
    
    echo "Erreur : Aucun UID disponible trouvé dans la plage $start_uid-$max_uid"
    return 1
}

# Créer un compte utilisateur avec paramètres entreprise
create_enterprise_user() {
    local username="$1"
    local real_name="$2"
    local password="$3"
    local user_type="${4:-standard}"
    local department="${5:-General}"
    local admin_user=$(whoami)
    
    log_audit_action "USER_CREATION_START" "$username" "$admin_user" "type=$user_type,department=$department"
    
    # Valider les entrées
    if ! validate_username "$username"; then
        log_operation "ERROR" "Validation du nom d'utilisateur échouée pour : $username"
        return 1
    fi
    
    if [[ "$REQUIRE_SECURE_PASSWORDS" == "true" ]] && ! validate_password "$password"; then
        log_operation "ERROR" "Validation du mot de passe échouée pour l'utilisateur : $username"
        return 1
    fi
    
    # Trouver l'UID disponible
    local uid
    uid=$(find_next_uid)
    if [[ $? -ne 0 ]]; then
        log_operation "ERROR" "Échec de trouver un UID disponible pour : $username"
        return 1
    fi
    
    echo "=== Création Utilisateur Entreprise : $username ==="
    echo "Nom Réel : $real_name"
    echo "Type Utilisateur : $user_type"
    echo "Département : $department"
    echo "UID Assigné : $uid"
    echo "Administrateur : $admin_user"
    echo ""
    
    # Créer le compte utilisateur avec dscl
    echo "Création du compte utilisateur..."
    
    # Création utilisateur de base
    if ! sudo dscl . -create "/Users/$username"; then
        log_operation "ERROR" "Échec de créer l'utilisateur : $username"
        return 1
    fi
    
    # Définir le nom réel
    sudo dscl . -create "/Users/$username" RealName "$real_name"
    
    # Définir le mot de passe
    sudo dscl . -passwd "/Users/$username" "$password"
    
    # Définir l'UID
    sudo dscl . -create "/Users/$username" UniqueID "$uid"
    
    # Déterminer l'ID du groupe principal selon le type d'utilisateur
    local primary_gid
    case "$user_type" in
        "admin")
            primary_gid=80  # groupe admin
            ;;
        "developer")
            primary_gid=20  # groupe staff
            ;;
        "standard"|*)
            primary_gid=20  # groupe staff
            ;;
    esac
    
    sudo dscl . -create "/Users/$username" PrimaryGroupID "$primary_gid"
    
    # Définir le shell
    sudo dscl . -create "/Users/$username" UserShell "$DEFAULT_SHELL"
    
    # Créer le répertoire home
    local home_dir="$HOME_BASE_DIR/$username"
    sudo dscl . -create "/Users/$username" NFSHomeDirectory "$home_dir"
    
    # Ajouter les attributs entreprise
    sudo dscl . -create "/Users/$username" Department "$department"
    sudo dscl . -create "/Users/$username" Company "$(hostname -s | cut -d. -f1)"
    sudo dscl . -create "/Users/$username" CreationDate "$(date)"
    sudo dscl . -create "/Users/$username" CreatedBy "$admin_user"
    
    # Ajouter l'indice de mot de passe
    sudo dscl . -create "/Users/$username" hint "Contactez le support IT pour l'assistance mot de passe"
    
    # Configurer les appartenances aux groupes selon le type d'utilisateur
    echo "Configuration des appartenances aux groupes..."
    case "$user_type" in
        "admin")
            for group in "${ADMIN_GROUPS[@]}"; do
                sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null
            done
            ;;
        "developer")
            for group in "${DEVELOPER_GROUPS[@]}"; do
                sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null
            done
            ;;
        "standard"|*)
            for group in "${STANDARD_GROUPS[@]}"; do
                sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null
            done
            ;;
    esac
    
    # Créer et configurer le répertoire home
    echo "Configuration du répertoire home..."
    if [[ ! -d "$home_dir" ]]; then
        sudo mkdir -p "$home_dir"
        sudo chown "$username:staff" "$home_dir"
        sudo chmod 755 "$home_dir"
    fi
    
    # Copier le modèle utilisateur si disponible
    local template_dir="$TEMPLATES_DIR/$user_type"
    if [[ -d "$template_dir" ]]; then
        echo "Application du modèle utilisateur : $user_type"
        sudo cp -R "$template_dir/"* "$home_dir/" 2>/dev/null
        sudo chown -R "$username:staff" "$home_dir"
    fi
    
    # Activer FileVault pour le nouvel utilisateur si requis
    if [[ "$AUTO_FILEVAULT_ENABLE" == "true" ]]; then
        echo "Activation de l'accès FileVault pour l'utilisateur..."
        sudo fdesetup add -usertoadd "$username" 2>/dev/null || true
    fi
    
    # Générer le rapport de profil utilisateur
    local profile_file="$PROVISIONING_DIR/${username}_profile.txt"
    {
        echo "Profil Utilisateur MacFleet"
        echo "=========================="
        echo "Nom d'utilisateur : $username"
        echo "Nom Réel : $real_name"
        echo "UID : $uid"
        echo "GID : $primary_gid"
        echo "Type Utilisateur : $user_type"
        echo "Département : $department"
        echo "Répertoire Home : $home_dir"
        echo "Shell : $DEFAULT_SHELL"
        echo "Créé : $(date)"
        echo "Créé Par : $admin_user"
        echo "Groupes : $(groups "$username" 2>/dev/null | cut -d: -f2)"
        echo ""
        echo "Paramètres de Sécurité :"
        echo "- FileVault Activé : $AUTO_FILEVAULT_ENABLE"
        echo "- Mot de Passe Sécurisé : $REQUIRE_SECURE_PASSWORDS"
        echo "- Convention de Nommage : $ENFORCE_NAMING_CONVENTION"
    } > "$profile_file"
    
    echo "✅ Création utilisateur terminée avec succès"
    echo "Profil sauvegardé : $profile_file"
    
    log_operation "INFO" "Utilisateur créé avec succès : $username (UID : $uid, Type : $user_type)"
    log_audit_action "USER_CREATION_SUCCESS" "$username" "$admin_user" "uid=$uid,type=$user_type,groups=$(groups "$username" 2>/dev/null | cut -d: -f2)"
    
    return 0
}

# Création utilisateur en masse depuis fichier CSV
bulk_create_users() {
    local csv_file="$1"
    local admin_user=$(whoami)
    
    if [[ ! -f "$csv_file" ]]; then
        echo "Erreur : Fichier CSV non trouvé : $csv_file"
        return 1
    fi
    
    log_audit_action "BULK_CREATION_START" "multiple" "$admin_user" "source=$csv_file"
    
    echo "=== Création Utilisateur en Masse ==="
    echo "Fichier CSV : $csv_file"
    echo "Administrateur : $admin_user"
    echo ""
    
    local line_count=0
    local success_count=0
    local error_count=0
    local results_file="$PROVISIONING_DIR/bulk_creation_$(date +%Y%m%d_%H%M%S).log"
    
    # Lire le fichier CSV (format : nom_utilisateur,nom_reel,type_utilisateur,departement)
    while IFS=',' read -r username real_name user_type department; do
        line_count=$((line_count + 1))
        
        # Ignorer la ligne d'en-tête
        if [[ $line_count -eq 1 && "$username" == "username" ]]; then
            continue
        fi
        
        # Ignorer les lignes vides
        if [[ -z "$username" ]]; then
            continue
        fi
        
        # Générer un mot de passe sécurisé
        local password
        password=$(generate_secure_password 12 "high")
        
        echo "Traitement utilisateur $line_count : $username"
        
        # Créer l'utilisateur
        if create_enterprise_user "$username" "$real_name" "$password" "$user_type" "$department"; then
            success_count=$((success_count + 1))
            echo "SUCCÈS : $username,$real_name,$password,$user_type,$department" >> "$results_file"
        else
            error_count=$((error_count + 1))
            echo "ERREUR : $username,$real_name,ÉCHEC,$user_type,$department" >> "$results_file"
        fi
        
        echo ""
    done < "$csv_file"
    
    echo "=== Résumé Création en Masse ==="
    echo "Total Traité : $line_count"
    echo "Réussis : $success_count"
    echo "Erreurs : $error_count"
    echo "Fichier Résultats : $results_file"
    
    log_operation "INFO" "Création utilisateur en masse terminée : $success_count réussies, $error_count erreurs"
    log_audit_action "BULK_CREATION_COMPLETE" "multiple" "$admin_user" "total=$line_count,success=$success_count,errors=$error_count"
}

# Créer des modèles utilisateur
create_user_template() {
    local template_type="$1"
    local template_dir="$TEMPLATES_DIR/$template_type"
    
    echo "Création du modèle utilisateur : $template_type"
    
    mkdir -p "$template_dir"
    
    case "$template_type" in
        "standard")
            # Modèle utilisateur standard
            mkdir -p "$template_dir/Desktop"
            mkdir -p "$template_dir/Documents"
            mkdir -p "$template_dir/Downloads"
            
            # Créer le document de bienvenue
            cat > "$template_dir/Desktop/Welcome.txt" << EOF
Bienvenue sur MacFleet !

Votre compte a été configuré avec des privilèges utilisateur standard.
Pour le support, veuillez contacter IT à support@company.com

Type de Compte : Utilisateur Standard
Date de Création : $(date)
EOF
            ;;
        "admin")
            # Modèle utilisateur admin
            mkdir -p "$template_dir/Desktop"
            mkdir -p "$template_dir/Documents/OutilsAdmin"
            mkdir -p "$template_dir/Downloads"
            
            cat > "$template_dir/Desktop/Admin_Welcome.txt" << EOF
Bienvenue sur MacFleet - Compte Administrateur

Votre compte a été configuré avec des privilèges administratifs.
Veuillez utiliser ces privilèges de manière responsable.

Type de Compte : Administrateur
Date de Création : $(date)

Important :
- Suivez les politiques de sécurité de l'entreprise
- Changements de mot de passe réguliers requis
- Toutes les actions administratives sont enregistrées
EOF
            ;;
        "developer")
            # Modèle utilisateur développeur
            mkdir -p "$template_dir/Desktop"
            mkdir -p "$template_dir/Documents/Projets"
            mkdir -p "$template_dir/Downloads"
            mkdir -p "$template_dir/Development"
            
            cat > "$template_dir/Desktop/Developer_Setup.txt" << EOF
Configuration Compte Développeur

Votre compte inclut l'accès aux outils de développement.

Type de Compte : Développeur
Date de Création : $(date)

Étapes Suivantes :
1. Installer Xcode depuis l'App Store
2. Configurer les identifiants Git
3. Configurer l'environnement de développement
4. Consulter la documentation des standards de codage
EOF
            ;;
    esac
    
    # Définir les permissions du modèle
    chmod -R 755 "$template_dir"
    
    echo "Modèle créé : $template_dir"
    log_operation "INFO" "Modèle utilisateur créé : $template_type"
}

# Générer un rapport de provisioning
generate_provisioning_report() {
    local report_type="${1:-resume}"
    local admin_user=$(whoami)
    local report_file="$PROVISIONING_DIR/provisioning_report_$(date +%Y%m%d_%H%M%S).txt"
    
    log_audit_action "PROVISIONING_REPORT" "system" "$admin_user" "type=$report_type"
    
    {
        echo "Rapport de Provisioning Utilisateur MacFleet"
        echo "==========================================="
        echo "Type de Rapport : $report_type"
        echo "Généré : $(date)"
        echo "Généré Par : $admin_user"
        echo "Nom d'hôte : $(hostname)"
        echo ""
        
        case "$report_type" in
            "resume")
                echo "== Résumé de Provisioning =="
                local total_users=$(dscl . list /Users | grep -v '^_' | wc -l)
                local recent_users=$(find "$PROVISIONING_DIR" -name "*_profile.txt" -mtime -7 | wc -l)
                
                echo "Total Utilisateurs : $total_users"
                echo "Utilisateurs Créés (7 derniers jours) : $recent_users"
                echo ""
                
                echo "Distribution Type Utilisateur :"
                echo "Utilisateurs Standard : $(dscl . list /Users | xargs -I {} dscl . read /Users/{} PrimaryGroupID 2>/dev/null | grep -c '20')"
                echo "Utilisateurs Admin : $(dscl . list /Users | xargs -I {} dscl . read /Users/{} PrimaryGroupID 2>/dev/null | grep -c '80')"
                ;;
            "recent")
                echo "== Créations Utilisateur Récentes =="
                echo "Utilisateurs créés dans les 30 derniers jours :"
                find "$PROVISIONING_DIR" -name "*_profile.txt" -mtime -30 -exec basename {} \; | sed 's/_profile.txt//'
                ;;
            "audit")
                echo "== Information d'Audit =="
                if [[ -f "$AUDIT_LOG" ]]; then
                    echo "Activités de provisioning récentes :"
                    grep "USER_CREATION" "$AUDIT_LOG" | tail -10
                else
                    echo "Aucun log d'audit disponible"
                fi
                ;;
        esac
        
        echo ""
        echo "== Configuration =="
        echo "UID Min : $MIN_UID"
        echo "UID Max : $MAX_UID"
        echo "Shell Par Défaut : $DEFAULT_SHELL"
        echo "FileVault Auto : $AUTO_FILEVAULT_ENABLE"
        echo "Mots de Passe Sécurisés : $REQUIRE_SECURE_PASSWORDS"
        echo "Convention Nommage : $ENFORCE_NAMING_CONVENTION"
        
    } > "$report_file"
    
    echo "Rapport de provisioning généré : $report_file"
    log_operation "INFO" "Rapport de provisioning généré : $report_file"
}

# Fonction principale de gestion de création utilisateur
main() {
    local action="${1:-help}"
    
    case "$action" in
        "create")
            local username="$2"
            local real_name="$3"
            local password="$4"
            local user_type="${5:-standard}"
            local department="${6:-General}"
            
            if [[ -z "$username" || -z "$real_name" ]]; then
                echo "Usage : $0 create <nom_utilisateur> <nom_reel> [mot_de_passe] [type_utilisateur] [departement]"
                echo "Types utilisateur : standard, admin, developer"
                exit 1
            fi
            
            # Générer un mot de passe si non fourni
            if [[ -z "$password" ]]; then
                password=$(generate_secure_password 12 "high")
                echo "Mot de passe sécurisé généré : $password"
            fi
            
            create_enterprise_user "$username" "$real_name" "$password" "$user_type" "$department"
            ;;
        "bulk")
            local csv_file="$2"
            
            if [[ -z "$csv_file" ]]; then
                echo "Usage : $0 bulk <fichier_csv>"
                echo "Format CSV : nom_utilisateur,nom_reel,type_utilisateur,departement"
                exit 1
            fi
            
            bulk_create_users "$csv_file"
            ;;
        "template")
            local template_type="$2"
            
            if [[ -z "$template_type" ]]; then
                echo "Usage : $0 template <type_modele>"
                echo "Types de modèle : standard, admin, developer"
                exit 1
            fi
            
            create_user_template "$template_type"
            ;;
        "report")
            local report_type="${2:-resume}"
            
            generate_provisioning_report "$report_type"
            ;;
        "password")
            local length="${2:-12}"
            local complexity="${3:-high}"
            
            echo "Mot de passe généré : $(generate_secure_password "$length" "$complexity")"
            ;;
        "help"|*)
            echo "$SCRIPT_NAME v$VERSION"
            echo "Gestion Entreprise de Création Utilisateur"
            echo ""
            echo "Usage : $0 <action> [options]"
            echo ""
            echo "Actions :"
            echo "  create <nom_utilisateur> <nom_reel> [mot_de_passe] [type] [dept]  - Créer un utilisateur unique"
            echo "  bulk <fichier_csv>                                               - Créer des utilisateurs depuis CSV"
            echo "  template <type>                                                  - Créer un modèle utilisateur"
            echo "  report [type]                                                    - Générer des rapports de provisioning"
            echo "  password [longueur] [complexite]                                - Générer un mot de passe sécurisé"
            echo "  help                                                             - Afficher ce message d'aide"
            echo ""
            echo "Types Utilisateur :"
            echo "  standard    - Utilisateur standard avec privilèges de base"
            echo "  admin       - Utilisateur administratif avec privilèges élevés"
            echo "  developer   - Utilisateur développeur avec accès aux outils de développement"
            echo ""
            echo "Types de Rapport :"
            echo "  resume      - Aperçu du provisioning utilisateur (défaut)"
            echo "  recent      - Utilisateurs récemment créés"
            echo "  audit       - Information de piste d'audit"
            echo ""
            echo "Complexité Mot de Passe :"
            echo "  basic       - Minuscules et chiffres uniquement"
            echo "  medium      - Lettres et chiffres"
            echo "  high        - Lettres, chiffres et symboles (défaut)"
            echo ""
            echo "Fonctionnalités :"
            echo "  • Provisioning utilisateur automatisé avec modèles entreprise"
            echo "  • Création de comptes axée sécurité avec validation"
            echo "  • Création utilisateur en masse depuis fichiers CSV"
            echo "  • Journalisation d'audit complète et conformité"
            echo "  • Intégration avec FileVault et sécurité entreprise"
            echo "  • Intégration utilisateur basée sur modèles"
            echo "  • Génération et validation automatisées de mots de passe"
            ;;
    esac
}

# Exécuter la fonction principale avec tous les arguments
main "$@"

Commandes de Référence Rapide

Création Utilisateur Unique

# Créer un utilisateur standard
./user_creator.sh create jean.dupont "Jean Dupont"

# Créer un utilisateur admin avec mot de passe personnalisé
./user_creator.sh create admin.utilisateur "Utilisateur Admin" "MotDePasseSecurise123!" admin IT

# Créer un utilisateur développeur
./user_creator.sh create dev.utilisateur "Utilisateur Développeur" "" developer Ingenierie

# Créer un utilisateur avec tous les paramètres
./user_creator.sh create jane.smith "Jane Smith" "MotDePassePerso456!" standard Marketing

Opérations Utilisateur en Masse

# Créer des utilisateurs depuis un fichier CSV
./user_creator.sh bulk utilisateurs.csv

# Exemple de format CSV :
# nom_utilisateur,nom_reel,type_utilisateur,departement
# jean.dupont,Jean Dupont,standard,Ventes
# jane.admin,Jane Admin,admin,IT
# dev.utilisateur,Utilisateur Dev,developer,Ingenierie

Gestion de Modèles

# Créer un modèle utilisateur standard
./user_creator.sh template standard

# Créer un modèle utilisateur admin
./user_creator.sh template admin

# Créer un modèle utilisateur développeur
./user_creator.sh template developer

Génération de Mot de Passe

# Générer un mot de passe haute complexité (défaut)
./user_creator.sh password

# Générer un mot de passe de 16 caractères
./user_creator.sh password 16

# Générer un mot de passe complexité moyenne
./user_creator.sh password 12 medium

# Générer un mot de passe basique
./user_creator.sh password 10 basic

Opérations de Rapport

# Générer un rapport résumé
./user_creator.sh report

# Générer un rapport utilisateurs récents
./user_creator.sh report recent

# Générer un rapport d'audit
./user_creator.sh report audit

Exemples d'Intégration

Intégration JAMF Pro

#!/bin/bash

# Script JAMF Pro pour création utilisateur entreprise
# Paramètres : $4 = nom_utilisateur, $5 = nom_reel, $6 = type_utilisateur, $7 = departement

NOM_UTILISATEUR="$4"
NOM_REEL="$5"
TYPE_UTILISATEUR="$6"
DEPARTEMENT="$7"

# Télécharger le créateur utilisateur s'il n'est pas présent
if [[ ! -f "/usr/local/bin/macfleet_user_creator.sh" ]]; then
    curl -o "/usr/local/bin/macfleet_user_creator.sh" \
         "https://scripts.macfleet.com/user_creator.sh"
    chmod +x "/usr/local/bin/macfleet_user_creator.sh"
fi

# Créer l'utilisateur avec paramètres entreprise
/usr/local/bin/macfleet_user_creator.sh create \
    "$NOM_UTILISATEUR" "$NOM_REEL" "" "$TYPE_UTILISATEUR" "$DEPARTEMENT"

# Rapporter le statut à JAMF
if [[ $? -eq 0 ]]; then
    echo "Utilisateur $NOM_UTILISATEUR créé avec succès"
    exit 0
else
    echo "Échec de création de l'utilisateur $NOM_UTILISATEUR"
    exit 1
fi

Fonctionnalités de Sécurité et Conformité

Application de Politique de Mot de Passe

# Validation avancée de politique de mot de passe
enforce_enterprise_password_policy() {
    local password="$1"
    local username="$2"
    
    # Vérifier contre les mots de passe communs
    local common_passwords=("password" "123456" "admin" "welcome")
    for common in "${common_passwords[@]}"; do
        if [[ "${password,,}" == "${common,,}" ]]; then
            echo "Erreur : Mot de passe trop commun"
            return 1
        fi
    done
    
    # Vérifier le nom d'utilisateur dans le mot de passe
    if [[ "${password,,}" =~ ${username,,} ]]; then
        echo "Erreur : Le mot de passe ne peut pas contenir le nom d'utilisateur"
        return 1
    fi
    
    # Vérifier l'historique des mots de passe (si implémenté)
    check_password_history "$username" "$password"
}

Rapport d'Audit et Conformité

# Générer un rapport de conformité pour la création utilisateur
generate_compliance_report() {
    local start_date="$1"
    local end_date="$2"
    local report_file="/var/reports/user_creation_compliance_$(date +%Y%m%d).json"
    
    {
        echo "{"
        echo "  \"report_type\": \"user_creation_compliance\","
        echo "  \"period\": \"$start_date à $end_date\","
        echo "  \"generated\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
        echo "  \"total_users_created\": $(grep "USER_CREATION_SUCCESS" "$AUDIT_LOG" | wc -l),"
        echo "  \"policy_violations\": $(grep "POLICY_VIOLATION" "$AUDIT_LOG" | wc -l),"
        echo "  \"security_reviews\": $(grep "SECURITY_REVIEW" "$AUDIT_LOG" | wc -l)"
        echo "}"
    } > "$report_file"
    
    echo "Rapport de conformité généré : $report_file"
}

Meilleures Pratiques

  1. Utiliser des politiques de mots de passe forts avec exigences de complexité
  2. Implémenter des types d'utilisateur basés sur les rôles pour attribution appropriée des privilèges
  3. Activer la journalisation d'audit complète pour toutes les activités de création utilisateur
  4. Utiliser des modèles pour des expériences d'intégration utilisateur cohérentes
  5. Intégrer avec les services d'annuaire d'entreprise pour une gestion centralisée
  6. Automatiser l'inscription FileVault pour la conformité de sécurité
  7. Générer des rapports de conformité réguliers à des fins d'audit
  8. Valider les noms d'utilisateur selon les conventions de nommage d'entreprise

Ce système de gestion de création utilisateur entreprise fournit des capacités de provisioning utilisateur complètes avec contrôles de sécurité, conformité d'audit et workflows automatisés pour une gestion efficace du cycle de vie utilisateur MacFleet.

Gestion des Comptes Utilisateurs sur macOS

Maîtrisez la création et la gestion des comptes utilisateurs sur vos appareils MacFleet en utilisant des outils en ligne de commande puissants. Ce tutoriel couvre la création d'utilisateurs administrateurs et standards, la gestion des mots de passe, la configuration des comptes et la gestion avancée du cycle de vie des utilisateurs pour les déploiements en entreprise.

Comprendre la Gestion des Utilisateurs macOS

macOS fournit plusieurs outils en ligne de commande pour la gestion des comptes utilisateurs :

  • sysadminctl - Outil moderne de gestion des comptes utilisateurs (macOS 10.10+)
  • dscl - Utilitaire en ligne de commande des services d'annuaire pour les opérations avancées
  • passwd - Gestion et changement des mots de passe
  • id - Affichage des informations utilisateur et groupe
  • whoami - Identification de l'utilisateur actuel

Création Basique de Comptes Utilisateurs

Créer un Compte Utilisateur Administrateur

#!/bin/sh

# Définir la variable d'environnement PATH
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

# Configuration utilisateur administrateur
USERNAME="Daniel"
FULLNAME="Daniel.Hector"
PASSWORD="One@Two#8"
PASSWORDHINT="One to Eight"

# Créer un compte utilisateur administrateur
sysadminctl -addUser "$USERNAME" -fullName "$FULLNAME" -password "$PASSWORD" -hint "$PASSWORDHINT" -admin

echo "Compte utilisateur administrateur '$USERNAME' créé avec succès"

Créer un Compte Utilisateur Standard

#!/bin/sh

# Définir la variable d'environnement PATH
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

# Configuration utilisateur standard
USERNAME="Daniel"
FULLNAME="Daniel.Hector"
PASSWORD="One@Two#8"
PASSWORDHINT="One to Eight"

# Créer un compte utilisateur standard (pas de flag -admin)
sysadminctl -addUser "$USERNAME" -fullName "$FULLNAME" -password "$PASSWORD" -hint "$PASSWORDHINT"

echo "Compte utilisateur standard '$USERNAME' créé avec succès"

Création d'Utilisateur Améliorée avec Validation

#!/bin/bash

# Création d'utilisateur améliorée avec validation
create_user_account() {
    local username="$1"
    local fullname="$2"
    local password="$3"
    local hint="$4"
    local is_admin="${5:-false}"
    
    # Valider les entrées
    if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
        echo "Erreur : Le nom d'utilisateur, le nom complet et le mot de passe sont requis"
        return 1
    fi
    
    # Vérifier si l'utilisateur existe déjà
    if id "$username" &>/dev/null; then
        echo "Erreur : L'utilisateur '$username' existe déjà"
        return 1
    fi
    
    # Définir l'environnement PATH
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    # Construire la commande sysadminctl
    local cmd="sysadminctl -addUser \"$username\" -fullName \"$fullname\" -password \"$password\""
    
    if [[ -n "$hint" ]]; then
        cmd="$cmd -hint \"$hint\""
    fi
    
    if [[ "$is_admin" == "true" ]]; then
        cmd="$cmd -admin"
        echo "Création d'un utilisateur administrateur : $username"
    else
        echo "Création d'un utilisateur standard : $username"
    fi
    
    # Exécuter la création d'utilisateur
    if eval "$cmd"; then
        echo "✓ Utilisateur '$username' créé avec succès"
        
        # Afficher les informations utilisateur
        echo "Détails de l'utilisateur :"
        id "$username"
        return 0
    else
        echo "✗ Échec de la création de l'utilisateur '$username'"
        return 1
    fi
}

# Exemples d'utilisation
create_user_account "daniel" "Daniel Hector" "SecurePass123!" "Indice de mot de passe" "true"
create_user_account "jane" "Jane Smith" "UserPass456!" "Autre indice" "false"

Gestion Avancée des Utilisateurs

Création d'Utilisateurs en Lot

#!/bin/bash

# Création d'utilisateurs en lot à partir de configuration
batch_create_users() {
    local config_file="$1"
    
    if [[ ! -f "$config_file" ]]; then
        echo "Erreur : Fichier de configuration introuvable : $config_file"
        return 1
    fi
    
    echo "=== Création d'Utilisateurs en Lot ==="
    
    local success_count=0
    local error_count=0
    
    # Lire le fichier de configuration (format : username,fullname,password,hint,admin)
    while IFS=',' read -r username fullname password hint is_admin; do
        # Ignorer les lignes vides et les commentaires
        [[ -z "$username" || "$username" =~ ^# ]] && continue
        
        echo "Traitement de l'utilisateur : $username"
        
        if create_user_account "$username" "$fullname" "$password" "$hint" "$is_admin"; then
            ((success_count++))
        else
            ((error_count++))
        fi
        
        echo "---"
    done < "$config_file"
    
    echo "Création en lot terminée :"
    echo "✓ Succès : $success_count utilisateurs"
    echo "✗ Erreurs : $error_count utilisateurs"
}

# Créer un fichier de configuration exemple
create_user_config() {
    local config_file="/tmp/users_config.csv"
    
    cat > "$config_file" << EOF
# Format : username,fullname,password,hint,admin(true/false)
daniel,Daniel Hector,SecurePass123!,Indice de mot de passe,true
jane,Jane Smith,UserPass456!,Autre indice,false
alex,Alex Johnson,TempPass789!,Mot de passe temporaire,false
admin,Administrateur Système,AdminPass000!,Accès administrateur,true
EOF
    
    echo "Configuration exemple créée : $config_file"
    echo "$config_file"
}

# Utilisation
config_file=$(create_user_config)
batch_create_users "$config_file"

Modification de Comptes Utilisateurs

#!/bin/bash

# Modifier les comptes utilisateurs existants
modify_user_account() {
    local username="$1"
    local action="$2"
    local value="$3"
    
    # Vérifier que l'utilisateur existe
    if ! id "$username" &>/dev/null; then
        echo "Erreur : L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    case "$action" in
        "password")
            echo "Changement de mot de passe pour l'utilisateur : $username"
            if sysadminctl -resetPasswordFor "$username" -newPassword "$value"; then
                echo "✓ Mot de passe changé avec succès"
            else
                echo "✗ Échec du changement de mot de passe"
                return 1
            fi
            ;;
        "fullname")
            echo "Changement du nom complet pour l'utilisateur : $username"
            if dscl . -change "/Users/$username" RealName "$(dscl . -read "/Users/$username" RealName | cut -d: -f2 | xargs)" "$value"; then
                echo "✓ Nom complet changé en : $value"
            else
                echo "✗ Échec du changement de nom complet"
                return 1
            fi
            ;;
        "admin")
            if [[ "$value" == "true" ]]; then
                echo "Attribution des privilèges administrateur à : $username"
                if dseditgroup -o edit -a "$username" -t user admin; then
                    echo "✓ Privilèges administrateur attribués"
                else
                    echo "✗ Échec de l'attribution des privilèges administrateur"
                    return 1
                fi
            else
                echo "Suppression des privilèges administrateur de : $username"
                if dseditgroup -o edit -d "$username" -t user admin; then
                    echo "✓ Privilèges administrateur supprimés"
                else
                    echo "✗ Échec de la suppression des privilèges administrateur"
                    return 1
                fi
            fi
            ;;
        "enable")
            echo "Activation du compte utilisateur : $username"
            if dscl . -create "/Users/$username" AuthenticationAuthority; then
                echo "✓ Compte utilisateur activé"
            else
                echo "✗ Échec de l'activation du compte utilisateur"
                return 1
            fi
            ;;
        "disable")
            echo "Désactivation du compte utilisateur : $username"
            if dscl . -delete "/Users/$username" AuthenticationAuthority; then
                echo "✓ Compte utilisateur désactivé"
            else
                echo "✗ Échec de la désactivation du compte utilisateur"
                return 1
            fi
            ;;
        *)
            echo "Erreur : Action inconnue '$action'"
            echo "Actions disponibles : password, fullname, admin, enable, disable"
            return 1
            ;;
    esac
}

# Exemples d'utilisation
modify_user_account "daniel" "password" "NewSecurePass123!"
modify_user_account "jane" "admin" "true"
modify_user_account "alex" "fullname" "Alexander Johnson"

Suppression de Comptes Utilisateurs

#!/bin/bash

# Supprimer les comptes utilisateurs avec options
delete_user_account() {
    local username="$1"
    local delete_home="${2:-true}"
    local backup_home="${3:-false}"
    
    # Vérifier que l'utilisateur existe
    if ! id "$username" &>/dev/null; then
        echo "Erreur : L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    # Empêcher la suppression d'utilisateurs système critiques
    local system_users=("root" "daemon" "nobody" "_www" "_mysql" "_postgresql")
    for sys_user in "${system_users[@]}"; do
        if [[ "$username" == "$sys_user" ]]; then
            echo "Erreur : Impossible de supprimer l'utilisateur système '$username'"
            return 1
        fi
    done
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    echo "Préparation de la suppression de l'utilisateur : $username"
    
    # Sauvegarder le répertoire home si demandé
    if [[ "$backup_home" == "true" ]]; then
        local backup_dir="/var/backups/deleted_users"
        local timestamp=$(date +%Y%m%d_%H%M%S)
        local backup_path="$backup_dir/${username}_${timestamp}.tar.gz"
        
        mkdir -p "$backup_dir"
        
        echo "Sauvegarde du répertoire home vers : $backup_path"
        if tar -czf "$backup_path" -C "/Users" "$username" 2>/dev/null; then
            echo "✓ Répertoire home sauvegardé"
        else
            echo "⚠ Attention : Échec de la sauvegarde du répertoire home"
        fi
    fi
    
    # Supprimer le compte utilisateur
    local delete_cmd="sysadminctl -deleteUser \"$username\""
    
    if [[ "$delete_home" == "true" ]]; then
        delete_cmd="$delete_cmd -secure"
        echo "Suppression de l'utilisateur et du répertoire home..."
    else
        echo "Suppression du compte utilisateur uniquement..."
    fi
    
    if eval "$delete_cmd"; then
        echo "✓ Utilisateur '$username' supprimé avec succès"
        return 0
    else
        echo "✗ Échec de la suppression de l'utilisateur '$username'"
        return 1
    fi
}

# Exemples d'utilisation
delete_user_account "testuser" "true" "true"  # Supprimer avec home, sauvegarder d'abord
delete_user_account "tempuser" "false" "false"  # Supprimer utilisateur seulement, pas de sauvegarde

Système de Gestion d'Utilisateurs en Entreprise

#!/bin/bash

# Outil de Gestion d'Utilisateurs MacFleet
# Gestion complète des comptes utilisateurs pour les appareils de flotte

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_users.log"
REPORT_DIR="/etc/macfleet/reports/users"
CONFIG_DIR="/etc/macfleet/users"
BACKUP_DIR="/var/backups/macfleet_users"

# Créer les répertoires s'ils n'existent pas
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$BACKUP_DIR"

# Catégories de comptes utilisateurs
declare -A USER_CATEGORIES=(
    ["administrator"]="admin,full_privileges,system_access"
    ["developer"]="standard,sudo_group,development_access"
    ["standard_user"]="standard,basic_privileges,user_access"
    ["service_account"]="standard,no_login,service_access"
    ["temporary_user"]="standard,limited_time,restricted_access"
    ["guest_user"]="standard,guest_privileges,temporary_access"
    ["kiosk_user"]="standard,kiosk_mode,restricted_access"
    ["backup_operator"]="standard,backup_privileges,system_access"
    ["monitoring_user"]="standard,read_only,monitoring_access"
    ["deployment_user"]="admin,deployment_privileges,automated_access"
)

# Politiques de gestion d'utilisateurs
declare -A USER_POLICIES=(
    ["password_strength"]="minimum_8_chars,mixed_case,numbers,special_chars"
    ["password_expiry"]="90_days,180_days,365_days,never"
    ["account_lockout"]="3_attempts,5_attempts,10_attempts,disabled"
    ["session_timeout"]="15_minutes,30_minutes,60_minutes,4_hours"
    ["home_directory"]="local_only,network_shared,encrypted,no_home"
    ["shell_access"]="/bin/bash,/bin/zsh,/usr/bin/false,/sbin/nologin"
)

# Fonction de journalisation
log_action() {
    local message="$1"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] $message" | tee -a "$LOG_FILE"
}

# Création d'utilisateur améliorée avec fonctionnalités d'entreprise
create_enterprise_user() {
    local username="$1"
    local fullname="$2"
    local password="$3"
    local category="${4:-standard_user}"
    local custom_options="$5"
    
    log_action "Création d'utilisateur d'entreprise : $username (Catégorie : $category)"
    
    # Valider les entrées
    if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
        log_action "ERREUR : Le nom d'utilisateur, le nom complet et le mot de passe sont requis"
        return 1
    fi
    
    # Vérifier si l'utilisateur existe déjà
    if id "$username" &>/dev/null; then
        log_action "ERREUR : L'utilisateur '$username' existe déjà"
        return 1
    fi
    
    # Valider la force du mot de passe
    if ! validate_password_strength "$password"; then
        log_action "ERREUR : Le mot de passe ne respecte pas les exigences de force"
        return 1
    fi
    
    # Générer un UID unique
    local new_uid=$(get_next_available_uid)
    
    # Créer un compte utilisateur basé sur la catégorie
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    local is_admin="false"
    local shell="/bin/bash"
    local home_dir="/Users/$username"
    
    # Analyser la configuration de catégorie
    IFS=',' read -ra CATEGORY_PARTS <<< "${USER_CATEGORIES[$category]}"
    local user_type="${CATEGORY_PARTS[0]}"
    local privileges="${CATEGORY_PARTS[1]}"
    local access_level="${CATEGORY_PARTS[2]}"
    
    [[ "$user_type" == "admin" ]] && is_admin="true"
    [[ "$privileges" == "no_login" ]] && shell="/usr/bin/false"
    
    # Créer le compte utilisateur
    local create_cmd="sysadminctl -addUser \"$username\" -fullName \"$fullname\" -password \"$password\" -UID \"$new_uid\""
    
    if [[ "$is_admin" == "true" ]]; then
        create_cmd="$create_cmd -admin"
    fi
    
    if eval "$create_cmd"; then
        log_action "SUCCÈS : Utilisateur '$username' créé avec UID $new_uid"
        
        # Appliquer des configurations supplémentaires
        configure_user_environment "$username" "$category" "$custom_options"
        
        # Générer un rapport utilisateur
        local report_file="$REPORT_DIR/user_creation_${username}_$(date +%Y%m%d_%H%M%S).json"
        generate_user_report "$username" "$report_file"
        
        echo "$report_file"
        return 0
    else
        log_action "ERREUR : Échec de la création de l'utilisateur '$username'"
        return 1
    fi
}

# Validation de la force du mot de passe
validate_password_strength() {
    local password="$1"
    local min_length=8
    
    # Vérifier la longueur minimale
    if [[ ${#password} -lt $min_length ]]; then
        echo "Le mot de passe doit contenir au moins $min_length caractères"
        return 1
    fi
    
    # Vérifier la présence d'une majuscule
    if [[ ! "$password" =~ [A-Z] ]]; then
        echo "Le mot de passe doit contenir au moins une majuscule"
        return 1
    fi
    
    # Vérifier la présence d'une minuscule
    if [[ ! "$password" =~ [a-z] ]]; then
        echo "Le mot de passe doit contenir au moins une minuscule"
        return 1
    fi
    
    # Vérifier la présence d'un chiffre
    if [[ ! "$password" =~ [0-9] ]]; then
        echo "Le mot de passe doit contenir au moins un chiffre"
        return 1
    fi
    
    # Vérifier la présence d'un caractère spécial
    if [[ ! "$password" =~ [^a-zA-Z0-9] ]]; then
        echo "Le mot de passe doit contenir au moins un caractère spécial"
        return 1
    fi
    
    return 0
}

# Obtenir le prochain UID disponible
get_next_available_uid() {
    local start_uid=1000
    local max_uid=65533
    
    for ((uid=start_uid; uid<=max_uid; uid++)); do
        if ! id -u "$uid" &>/dev/null; then
            echo "$uid"
            return 0
        fi
    done
    
    echo "65534"  # UID de secours
}

# Configurer l'environnement utilisateur basé sur la catégorie
configure_user_environment() {
    local username="$1"
    local category="$2"
    local custom_options="$3"
    
    log_action "Configuration de l'environnement pour l'utilisateur : $username (Catégorie : $category)"
    
    case "$category" in
        "developer")
            # Ajouter au groupe développeur
            dseditgroup -o create -q developer 2>/dev/null
            dseditgroup -o edit -a "$username" -t user developer
            
            # Accorder l'accès sudo pour le développement
            echo "$username ALL=(ALL) NOPASSWD: /usr/bin/xcodebuild, /usr/local/bin/brew" > "/etc/sudoers.d/$username"
            ;;
        "service_account")
            # Désactiver le shell de connexion
            dscl . -create "/Users/$username" UserShell /usr/bin/false
            
            # Masquer de la fenêtre de connexion
            dscl . -create "/Users/$username" IsHidden 1
            ;;
        "kiosk_user")
            # Configurer l'environnement kiosk
            setup_kiosk_user "$username"
            ;;
        "temporary_user")
            # Définir l'expiration du compte (30 jours)
            local expiry_date=$(date -v +30d +%Y-%m-%d)
            dscl . -create "/Users/$username" AccountExpires "$expiry_date"
            ;;
    esac
    
    # Appliquer les options personnalisées si fournies
    if [[ -n "$custom_options" ]]; then
        apply_custom_user_options "$username" "$custom_options"
    fi
}

# Configurer l'environnement utilisateur kiosk
setup_kiosk_user() {
    local username="$1"
    local kiosk_dir="/Users/$username/Desktop"
    
    # Créer l'environnement desktop kiosk
    mkdir -p "$kiosk_dir"
    
    # Créer le plist launchd pour le mode kiosk
    cat > "/Library/LaunchAgents/com.macfleet.kiosk.$username.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.kiosk.$username</string>
    <key>ProgramArguments</key>
    <array>
        <string>/System/Applications/Safari.app/Contents/MacOS/Safari</string>
        <string>--kiosk</string>
        <string>https://company-portal.example.com</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>$username</string>
</dict>
</plist>
EOF
    
    chown "$username:staff" "/Library/LaunchAgents/com.macfleet.kiosk.$username.plist"
    chmod 644 "/Library/LaunchAgents/com.macfleet.kiosk.$username.plist"
}

# Générer un rapport utilisateur
generate_user_report() {
    local username="$1"
    local report_file="$2"
    
    # Obtenir les informations utilisateur
    local user_info=$(id "$username")
    local user_groups=$(groups "$username")
    local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory | cut -d: -f2 | xargs)
    local shell=$(dscl . -read "/Users/$username" UserShell | cut -d: -f2 | xargs)
    local real_name=$(dscl . -read "/Users/$username" RealName | cut -d: -f2 | xargs)
    
    cat > "$report_file" << EOF
{
    "user_report": {
        "username": "$username",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "script_version": "$SCRIPT_VERSION",
        "user_details": {
            "real_name": "$real_name",
            "home_directory": "$home_dir",
            "shell": "$shell",
            "user_info": "$user_info",
            "groups": "$user_groups"
        },
        "creation_status": "success",
        "security_settings": {
            "password_policy_applied": true,
            "account_restrictions": [],
            "group_memberships": []
        }
    }
}
EOF
    
    log_action "Rapport utilisateur généré : $report_file"
}

# Gestion d'utilisateurs de flotte
manage_fleet_users() {
    local action="$1"
    local target_spec="$2"
    local options="$3"
    
    log_action "Gestion d'utilisateurs de flotte : $action"
    
    case "$action" in
        "audit")
            audit_fleet_users "$target_spec"
            ;;
        "sync")
            sync_fleet_users "$target_spec" "$options"
            ;;
        "cleanup")
            cleanup_fleet_users "$target_spec" "$options"
            ;;
        "report")
            generate_fleet_user_report
            ;;
    esac
}

# Auditer tous les utilisateurs du système
audit_fleet_users() {
    local filter_pattern="$1"
    
    echo "=== Audit des Utilisateurs de Flotte ==="
    
    local audit_report="$REPORT_DIR/fleet_user_audit_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$audit_report" << EOF
{
    "audit_info": {
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "filter_pattern": "$filter_pattern"
    },
    "user_accounts": [],
    "security_summary": {},
    "recommendations": []
}
EOF
    
    # Obtenir tous les utilisateurs locaux
    local users=($(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root"))
    
    for user in "${users[@]}"; do
        if [[ -z "$filter_pattern" || "$user" =~ $filter_pattern ]]; then
            # Obtenir les informations utilisateur détaillées
            local uid=$(id -u "$user" 2>/dev/null)
            local gid=$(id -g "$user" 2>/dev/null)
            local groups=$(groups "$user" 2>/dev/null)
            local home=$(dscl . -read "/Users/$user" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            local shell=$(dscl . -read "/Users/$user" UserShell 2>/dev/null | cut -d: -f2 | xargs)
            local last_login=$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}')
            
            # Vérifier si l'utilisateur est administrateur
            local is_admin="false"
            if dseditgroup -o checkmember -m "$user" admin &>/dev/null; then
                is_admin="true"
            fi
            
            # Ajouter au rapport
            jq --arg user "$user" \
               --arg uid "$uid" \
               --arg gid "$gid" \
               --arg groups "$groups" \
               --arg home "$home" \
               --arg shell "$shell" \
               --arg last_login "$last_login" \
               --arg is_admin "$is_admin" \
               '.user_accounts += [{
                   "username": $user,
                   "uid": $uid,
                   "gid": $gid,
                   "groups": $groups,
                   "home_directory": $home,
                   "shell": $shell,
                   "last_login": $last_login,
                   "is_admin": ($is_admin == "true")
               }]' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
        fi
    done
    
    # Générer un résumé de sécurité
    local total_users=$(echo "${users[@]}" | wc -w)
    local admin_users=$(dseditgroup -o checkmember -m "" admin 2>/dev/null | wc -l)
    local inactive_users=0
    
    # Vérifier les utilisateurs inactifs (pas de connexion depuis 90 jours)
    for user in "${users[@]}"; do
        local last_login_timestamp=$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}')
        if [[ -n "$last_login_timestamp" ]]; then
            local days_since_login=$(( ($(date +%s) - $(date -j -f "%b %d %H:%M" "$last_login_timestamp" +%s 2>/dev/null || echo 0)) / 86400 ))
            if [[ $days_since_login -gt 90 ]]; then
                ((inactive_users++))
            fi
        fi
    done
    
    jq --argjson total "$total_users" \
       --argjson admins "$admin_users" \
       --argjson inactive "$inactive_users" \
       '.security_summary = {
           "total_users": $total,
           "admin_users": $admins,
           "inactive_users": $inactive,
           "security_score": (100 - ($admins * 10) - ($inactive * 5))
       }' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    
    log_action "Audit des utilisateurs de flotte terminé : $audit_report"
    echo "$audit_report"
}

# Fonction d'exécution principale
main() {
    local action="${1:-create}"
    local username="${2:-}"
    local fullname="${3:-}"
    local password="${4:-}"
    local options="${5:-}"
    
    log_action "=== Gestion d'Utilisateurs MacFleet Démarrée ==="
    log_action "Action : $action, Utilisateur : $username"
    
    case "$action" in
        "create")
            if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
                echo "Utilisation : $0 create <username> <fullname> <password> [category]"
                exit 1
            fi
            create_enterprise_user "$username" "$fullname" "$password" "$options"
            ;;
        "modify")
            if [[ -z "$username" || -z "$fullname" ]]; then
                echo "Utilisation : $0 modify <username> <action> <value>"
                exit 1
            fi
            modify_user_account "$username" "$fullname" "$password"
            ;;
        "delete")
            if [[ -z "$username" ]]; then
                echo "Utilisation : $0 delete <username> [delete_home] [backup_home]"
                exit 1
            fi
            delete_user_account "$username" "$fullname" "$password"
            ;;
        "audit")
            audit_fleet_users "$username"
            ;;
        "fleet")
            manage_fleet_users "$username" "$fullname" "$password"
            ;;
        "help")
            echo "Utilisation : $0 [action] [options...]"
            echo "Actions :"
            echo "  create <username> <fullname> <password> [category] - Créer utilisateur"
            echo "  modify <username> <action> <value> - Modifier utilisateur"
            echo "  delete <username> [delete_home] [backup_home] - Supprimer utilisateur"
            echo "  audit [pattern] - Auditer utilisateurs"
            echo "  fleet <action> [pattern] [options] - Gestion de flotte"
            echo "  help - Afficher cette aide"
            echo ""
            echo "Catégories : ${!USER_CATEGORIES[*]}"
            ;;
        *)
            log_action "ERREUR : Action inconnue : $action"
            exit 1
            ;;
    esac
    
    log_action "=== Gestion d'utilisateurs terminée ==="
}

# Exécuter la fonction principale
main "$@"

Tâches Communes de Gestion d'Utilisateurs

Affichage des Informations Utilisateur

#!/bin/bash

# Afficher des informations complètes sur l'utilisateur
show_user_info() {
    local username="$1"
    
    if ! id "$username" &>/dev/null; then
        echo "L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    echo "=== Informations Utilisateur : $username ==="
    
    # Informations utilisateur de base
    echo "Informations ID Utilisateur :"
    id "$username"
    
    # Appartenance aux groupes
    echo -e "\nAppartenance aux Groupes :"
    groups "$username"
    
    # Informations répertoire home
    local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory | cut -d: -f2 | xargs)
    echo -e "\nRépertoire Home : $home_dir"
    if [[ -d "$home_dir" ]]; then
        echo "Taille du répertoire home : $(du -sh "$home_dir" | cut -f1)"
    fi
    
    # Shell de connexion
    local shell=$(dscl . -read "/Users/$username" UserShell | cut -d: -f2 | xargs)
    echo -e "\nShell de Connexion : $shell"
    
    # Statut du compte
    echo -e "\nStatut du Compte :"
    if dscl . -read "/Users/$username" AuthenticationAuthority &>/dev/null; then
        echo "Compte : Activé"
    else
        echo "Compte : Désactivé"
    fi
    
    # Statut administrateur
    if dseditgroup -o checkmember -m "$username" admin &>/dev/null; then
        echo "Privilèges Administrateur : Oui"
    else
        echo "Privilèges Administrateur : Non"
    fi
    
    # Dernière connexion
    echo -e "\nDernière Connexion :"
    last -1 "$username" | head -1
}

# Utilisation
show_user_info "daniel"

Gestion des Mots de Passe

#!/bin/bash

# Gestion complète des mots de passe
manage_user_password() {
    local username="$1"
    local action="$2"
    local new_password="$3"
    
    if ! id "$username" &>/dev/null; then
        echo "L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    case "$action" in
        "change")
            if [[ -z "$new_password" ]]; then
                echo "Nouveau mot de passe requis"
                return 1
            fi
            
            if ! validate_password_strength "$new_password"; then
                return 1
            fi
            
            if sysadminctl -resetPasswordFor "$username" -newPassword "$new_password"; then
                echo "Mot de passe changé avec succès pour l'utilisateur : $username"
                
                # Forcer le changement de mot de passe à la prochaine connexion (optionnel)
                # pwpolicy -u "$username" -setpolicy "newPasswordRequired=1"
            else
                echo "Échec du changement de mot de passe"
                return 1
            fi
            ;;
        "expire")
            echo "Expiration du mot de passe pour l'utilisateur : $username"
            if pwpolicy -u "$username" -setpolicy "newPasswordRequired=1"; then
                echo "Mot de passe expiré - l'utilisateur doit le changer à la prochaine connexion"
            else
                echo "Échec de l'expiration du mot de passe"
                return 1
            fi
            ;;
        "unlock")
            echo "Déverrouillage du compte pour l'utilisateur : $username"
            if pwpolicy -u "$username" -setpolicy "isDisabled=0"; then
                echo "Compte déverrouillé avec succès"
            else
                echo "Échec du déverrouillage du compte"
                return 1
            fi
            ;;
        *)
            echo "Action de mot de passe inconnue : $action"
            echo "Actions disponibles : change, expire, unlock"
            return 1
            ;;
    esac
}

# Utilisation
manage_user_password "daniel" "change" "NewSecurePassword123!"

Gestion des Groupes

#!/bin/bash

# Gestion des groupes d'utilisateurs
manage_user_groups() {
    local username="$1"
    local action="$2"
    local group_name="$3"
    
    if ! id "$username" &>/dev/null; then
        echo "L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    case "$action" in
        "add")
            echo "Ajout de l'utilisateur '$username' au groupe '$group_name'"
            if dseditgroup -o edit -a "$username" -t user "$group_name"; then
                echo "✓ Utilisateur ajouté au groupe avec succès"
            else
                echo "✗ Échec de l'ajout de l'utilisateur au groupe"
                return 1
            fi
            ;;
        "remove")
            echo "Suppression de l'utilisateur '$username' du groupe '$group_name'"
            if dseditgroup -o edit -d "$username" -t user "$group_name"; then
                echo "✓ Utilisateur supprimé du groupe avec succès"
            else
                echo "✗ Échec de la suppression de l'utilisateur du groupe"
                return 1
            fi
            ;;
        "list")
            echo "Groupes pour l'utilisateur '$username' :"
            groups "$username"
            ;;
        *)
            echo "Action de groupe inconnue : $action"
            echo "Actions disponibles : add, remove, list"
            return 1
            ;;
    esac
}

# Utilisation
manage_user_groups "daniel" "add" "developers"
manage_user_groups "daniel" "list"

Notes Importantes

  • Privilèges administrateur requis pour la création et modification d'utilisateurs
  • Politiques de mots de passe doivent imposer des mots de passe forts pour la sécurité
  • Validation utilisateur - Toujours vérifier les entrées avant de créer des comptes
  • Permissions du répertoire home - Assurer la propriété et permissions appropriées
  • Sauvegarde des données utilisateur avant les opérations de suppression
  • Tester les scripts sur des comptes individuels avant le déploiement en flotte
  • Surveiller les activités utilisateur pour la conformité de sécurité

Suppression de Comptes Utilisateur et Gestion du Cycle de Vie sur macOS

Gérez le cycle de vie des comptes utilisateur et les processus de suppression sécurisée sur vos appareils MacFleet avec une gestion complète des utilisateurs, des politiques de rétention des données et des procédures de départ d'entreprise. Ce tutoriel couvre la suppression sécurisée des utilisateurs, l'archivage des données et la gestion du cycle de vie conforme aux réglementations.

Comprendre la Suppression de Comptes Utilisateur

La suppression de comptes utilisateur sur macOS implique plusieurs composants et considérations de sécurité :

  • Suppression de Compte - Supprimer le compte utilisateur des bases de données système
  • Gestion des Données - Traiter les répertoires personnels et fichiers associés
  • Jetons de Sécurité - Gérer les exigences de jeton sécurisé pour la suppression
  • Conformité d'Entreprise - Respecter les exigences de rétention des données et de confidentialité

Considérations d'Entreprise

Une suppression appropriée de compte utilisateur nécessite une planification d'entreprise :

  • Politiques de Rétention des Données - Conformité aux exigences légales et réglementaires
  • Protocoles de Sécurité - Assurer la suppression complète des données et la révocation d'accès
  • Exigences d'Audit - Maintenir les journaux de suppression pour le suivi de conformité
  • Procédures de Récupération - Capacités de sauvegarde et récupération avant suppression
  • Automatisation des Processus - Procédures de départ rationalisées pour les employés qui partent

Suppression de Base de Comptes Utilisateur

Prérequis et Exigences de Sécurité

#!/bin/bash

# Vérifier les prérequis pour la suppression d'utilisateur
check_deletion_prerequisites() {
    echo "=== Vérification des Prérequis de Suppression d'Utilisateur ==="
    
    # Vérifier si exécuté avec privilèges administrateur
    if [[ $EUID -ne 0 ]]; then
        echo "⚠️ Avertissement : Ce script nécessite des privilèges administrateur"
        echo "Exécuter avec : sudo $0"
    else
        echo "✓ Privilèges administrateur confirmés"
    fi
    
    # Vérifier l'accès disque complet de l'app Service
    echo ""
    echo "--- Vérification Accès Disque Complet ---"
    local tcc_db="/Library/Application Support/com.apple.TCC/TCC.db"
    if [[ -r "$tcc_db" ]]; then
        echo "✓ Base de données TCC accessible - Accès disque complet probablement accordé"
    else
        echo "⚠️ Avertissement : Base de données TCC non accessible"
        echo "Assurez-vous que l'app Service a l'Accès Disque Complet dans Préférences Système"
    fi
    
    # Vérifier les détenteurs de jeton sécurisé disponibles
    echo ""
    echo "--- Analyse Jeton Sécurisé ---"
    local secure_token_users=$(sysadminctl -secureTokenStatus 2>/dev/null | grep "Enabled" | wc -l | tr -d ' ')
    echo "Détenteurs de jeton sécurisé trouvés : $secure_token_users"
    
    if [[ $secure_token_users -lt 2 ]]; then
        echo "⚠️ Avertissement : Moins de 2 détenteurs de jeton sécurisé détectés"
        echo "Impossible de supprimer l'unique détenteur de jeton sécurisé"
        echo "Ajouter un autre utilisateur admin avec jeton sécurisé avant suppression"
    else
        echo "✓ Plusieurs détenteurs de jeton sécurisé disponibles"
    fi
}

# Usage
check_deletion_prerequisites

Suppression Sécurisée de Compte Utilisateur

#!/bin/bash

# Supprimer un compte utilisateur en toute sécurité avec validation
delete_user_account() {
    local username="$1"
    local method="${2:-sysadminctl}"  # sysadminctl ou dscl
    local backup_data="${3:-true}"
    
    if [[ -z "$username" ]]; then
        echo "Usage : delete_user_account <nom_utilisateur> [méthode] [sauvegarder_données]"
        echo "Méthodes : sysadminctl (par défaut), dscl"
        echo "Sauvegarder données : true (par défaut), false"
        return 1
    fi
    
    echo "=== Suppression Sécurisée de Compte Utilisateur ==="
    echo "Utilisateur cible : $username"
    echo "Méthode de suppression : $method"
    echo "Sauvegarder données : $backup_data"
    echo ""
    
    # Valider que l'utilisateur existe
    if ! id "$username" >/dev/null 2>&1; then
        echo "Erreur : L'utilisateur '$username' n'existe pas"
        return 1
    fi
    
    # Vérifier si l'utilisateur est actuellement connecté
    local logged_in_users=$(who | awk '{print $1}' | sort -u)
    if echo "$logged_in_users" | grep -q "^$username$"; then
        echo "⚠️ Avertissement : L'utilisateur '$username' est actuellement connecté"
        echo "Forcer la déconnexion ou attendre que l'utilisateur se déconnecte avant suppression"
        return 1
    fi
    
    # Vérifier le statut du jeton sécurisé
    local token_status=$(sysadminctl -secureTokenStatus "$username" 2>/dev/null | grep "Enabled")
    if [[ -n "$token_status" ]]; then
        echo "L'utilisateur '$username' a un jeton sécurisé"
        
        # Compter le total des détenteurs de jeton sécurisé
        local total_tokens=$(sysadminctl -secureTokenStatus 2>/dev/null | grep "Enabled" | wc -l | tr -d ' ')
        if [[ $total_tokens -eq 1 ]]; then
            echo "Erreur : Impossible de supprimer l'unique détenteur de jeton sécurisé"
            echo "Ajouter d'abord un autre utilisateur admin avec jeton sécurisé"
            return 1
        fi
    fi
    
    # Sauvegarder les données utilisateur si demandé
    if [[ "$backup_data" == "true" ]]; then
        echo "Création de sauvegarde des données utilisateur..."
        backup_user_data "$username"
    fi
    
    # Effectuer la suppression basée sur la méthode
    echo ""
    echo "--- Suppression du Compte Utilisateur ---"
    case "$method" in
        "sysadminctl")
            delete_user_sysadminctl "$username"
            ;;
        "dscl")
            delete_user_dscl "$username"
            ;;
        *)
            echo "Erreur : Méthode de suppression inconnue : $method"
            return 1
            ;;
    esac
}

# Supprimer utilisateur avec sysadminctl (macOS 10.13+)
delete_user_sysadminctl() {
    local username="$1"
    
    echo "Utilisation de sysadminctl pour supprimer l'utilisateur : $username"
    
    if sysadminctl -deleteUser "$username" 2>/dev/null; then
        echo "✓ Compte utilisateur '$username' supprimé avec succès avec sysadminctl"
        return 0
    else
        echo "✗ Échec de suppression de l'utilisateur '$username' avec sysadminctl"
        return 1
    fi
}

# Supprimer utilisateur avec dscl (méthode héritée)
delete_user_dscl() {
    local username="$1"
    
    echo "Utilisation de dscl pour supprimer l'utilisateur : $username"
    
    if dscl . delete "/Users/$username" 2>/dev/null; then
        echo "✓ Compte utilisateur '$username' supprimé avec succès avec dscl"
        return 0
    else
        echo "✗ Échec de suppression de l'utilisateur '$username' avec dscl"
        return 1
    fi
}

# Exemple d'utilisation (commenté pour sécurité)
# delete_user_account "employe_partant" "sysadminctl" "true"

Gestion des Données et Répertoires Utilisateur

#!/bin/bash

# Gestion complète des données utilisateur
manage_user_data() {
    local username="$1"
    local action="${2:-archive}"  # archive, delete, preserve
    local backup_location="${3:-/var/backups/user_data}"
    
    if [[ -z "$username" ]]; then
        echo "Usage : manage_user_data <nom_utilisateur> [action] [emplacement_sauvegarde]"
        echo "Actions : archive (par défaut), delete, preserve"
        return 1
    fi
    
    echo "=== Gestion des Données Utilisateur ==="
    echo "Nom d'utilisateur : $username"
    echo "Action : $action"
    echo "Emplacement de sauvegarde : $backup_location"
    echo ""
    
    local user_home="/Users/$username"
    
    # Vérifier si le répertoire personnel utilisateur existe
    if [[ ! -d "$user_home" ]]; then
        echo "Répertoire personnel utilisateur non trouvé : $user_home"
        return 1
    fi
    
    # Obtenir la taille du répertoire pour rapport
    local dir_size=$(du -sh "$user_home" 2>/dev/null | awk '{print $1}')
    echo "Taille du répertoire personnel utilisateur : $dir_size"
    
    case "$action" in
        "archive")
            archive_user_data "$username" "$backup_location"
            ;;
        "delete")
            delete_user_data "$username"
            ;;
        "preserve")
            preserve_user_data "$username"
            ;;
        *)
            echo "Erreur : Action inconnue : $action"
            return 1
            ;;
    esac
}

# Archiver les données utilisateur avant suppression
archive_user_data() {
    local username="$1"
    local backup_location="$2"
    
    echo "--- Archivage des Données Utilisateur ---"
    
    # Créer le répertoire de sauvegarde s'il n'existe pas
    mkdir -p "$backup_location"
    
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local archive_name="${username}_backup_${timestamp}.tar.gz"
    local archive_path="$backup_location/$archive_name"
    
    echo "Création de l'archive : $archive_path"
    
    # Créer une archive compressée du répertoire personnel utilisateur
    if tar -czf "$archive_path" -C "/Users" "$username" 2>/dev/null; then
        echo "✓ Données utilisateur archivées avec succès"
        
        # Créer un fichier de métadonnées
        local metadata_file="$backup_location/${username}_metadata_${timestamp}.json"
        cat > "$metadata_file" << EOF
{
    "backup_metadata": {
        "username": "$username",
        "backup_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "archive_file": "$archive_name",
        "archive_size": "$(du -sh "$archive_path" | awk '{print $1}')",
        "original_path": "/Users/$username",
        "backup_location": "$backup_location",
        "hostname": "$(hostname)",
        "created_by": "$(whoami)"
    }
}
EOF
        
        echo "✓ Fichier de métadonnées créé : $metadata_file"
        echo "Détails de l'archive :"
        echo "  Fichier : $archive_path"
        echo "  Taille : $(du -sh "$archive_path" | awk '{print $1}')"
        
        return 0
    else
        echo "✗ Échec de création de l'archive"
        return 1
    fi
}

# Supprimer les données et répertoires utilisateur
delete_user_data() {
    local username="$1"
    local user_home="/Users/$username"
    
    echo "--- Suppression des Données Utilisateur ---"
    echo "⚠️ AVERTISSEMENT : Ceci supprimera définitivement toutes les données utilisateur"
    echo "Répertoire cible : $user_home"
    
    # Vérification de sécurité - ne pas supprimer les répertoires système
    case "$username" in
        "root"|"admin"|"administrator"|"Guest"|"Shared")
            echo "Erreur : Impossible de supprimer les données utilisateur système : $username"
            return 1
            ;;
    esac
    
    if [[ "$user_home" == "/Users/"* && ${#username} -gt 2 ]]; then
        echo "Suppression du répertoire personnel utilisateur..."
        if rm -rf "$user_home" 2>/dev/null; then
            echo "✓ Données utilisateur supprimées avec succès : $user_home"
            return 0
        else
            echo "✗ Échec de suppression des données utilisateur : $user_home"
            return 1
        fi
    else
        echo "Erreur : Chemin de répertoire personnel invalide : $user_home"
        return 1
    fi
}

# Préserver les données utilisateur avec changement de propriété
preserve_user_data() {
    local username="$1"
    local user_home="/Users/$username"
    local preserved_name="${username}_preserved_$(date +%Y%m%d)"
    local preserved_path="/Users/$preserved_name"
    
    echo "--- Préservation des Données Utilisateur ---"
    echo "Renommage du répertoire utilisateur pour préservation"
    echo "De : $user_home"
    echo "Vers : $preserved_path"
    
    if mv "$user_home" "$preserved_path" 2>/dev/null; then
        # Changer la propriété vers l'utilisateur admin
        chown -R root:admin "$preserved_path" 2>/dev/null
        chmod -R 755 "$preserved_path" 2>/dev/null
        
        echo "✓ Données utilisateur préservées à : $preserved_path"
        echo "✓ Propriété changée vers root:admin"
        return 0
    else
        echo "✗ Échec de préservation des données utilisateur"
        return 1
    fi
}

# Exemple d'utilisation
# manage_user_data "employe_partant" "archive" "/var/backups/user_data"

Système de Gestion du Cycle de Vie d'Entreprise

#!/bin/bash

# Outil de Suppression de Comptes Utilisateur et Gestion du Cycle de Vie MacFleet
# Départ d'entreprise complet, gestion des données et conformité

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_user_lifecycle.log"
REPORT_DIR="/etc/macfleet/reports/users"
CONFIG_DIR="/etc/macfleet/user_management"
POLICY_DIR="/etc/macfleet/policies/users"
BACKUP_DIR="/var/backups/macfleet/users"
COMPLIANCE_DIR="/etc/macfleet/compliance/users"

# Créer les répertoires s'ils n'existent pas
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$POLICY_DIR" "$BACKUP_DIR" "$COMPLIANCE_DIR"

# Politiques de cycle de vie utilisateur
declare -A LIFECYCLE_POLICIES=(
    ["immediate_deletion"]="delete_account,delete_data,no_backup,audit_log"
    ["secure_archival"]="backup_data,delete_account,delete_data,compliance_report"
    ["data_preservation"]="backup_data,preserve_home,delete_account,extended_audit"
    ["legal_hold"]="preserve_all,disable_account,legal_compliance,no_deletion"
    ["healthcare_hipaa"]="encrypted_backup,secure_deletion,hipaa_compliance,audit_trail"
    ["financial_compliance"]="full_backup,sox_compliance,retention_policy,secure_deletion"
    ["education_ferpa"]="student_data_protection,ferpa_compliance,selective_backup,audit_log"
    ["government_classified"]="classified_data_handling,security_clearance_check,secure_deletion,audit_trail"
    ["contractor_offboarding"]="project_data_separation,limited_backup,quick_deletion,access_revocation"
    ["temporary_disable"]="disable_only,preserve_all,no_deletion,reactivation_ready"
)

# Périodes de rétention des données (en jours)
declare -A RETENTION_PERIODS=(
    ["immediate"]="0"
    ["short_term"]="30"
    ["medium_term"]="90"
    ["long_term"]="365"
    ["legal_hold"]="indefinite"
    ["compliance_minimum"]="2555"  # 7 ans
)

# Cadres de conformité
declare -A COMPLIANCE_FRAMEWORKS=(
    ["hipaa"]="healthcare_data_protection,encrypted_storage,audit_logs,secure_deletion"
    ["sox"]="financial_records_retention,change_management,access_controls,audit_trail"
    ["ferpa"]="student_privacy,educational_records,consent_management,access_restrictions"
    ["gdpr"]="data_minimization,consent_withdrawal,right_to_erasure,data_portability"
    ["pci_dss"]="payment_data_protection,secure_deletion,access_monitoring,compliance_reporting"
)

# Fonction de journalisation
log_action() {
    local message="$1"
    local severity="${2:-INFO}"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$severity] $message" | tee -a "$LOG_FILE"
}

# Suppression de compte utilisateur d'entreprise avec fonctionnalités avancées
enterprise_user_deletion() {
    local username="$1"
    local policy="${2:-secure_archival}"
    local compliance_framework="${3:-}"
    local retention_period="${4:-medium_term}"
    local authorized_by="${5:-$(whoami)}"
    
    log_action "Démarrage du processus de suppression d'utilisateur d'entreprise" "INFO"
    log_action "Nom d'utilisateur : $username, Politique : $policy, Autorisé par : $authorized_by" "INFO"
    
    echo "=== Processus de Suppression d'Utilisateur d'Entreprise ==="
    echo "Nom d'utilisateur : $username"
    echo "Politique : $policy"
    echo "Cadre de Conformité : $compliance_framework"
    echo "Période de Rétention : $retention_period"
    echo "Autorisé Par : $authorized_by"
    echo "ID de Processus : $(uuidgen)"
    echo ""
    
    # Valider que l'utilisateur existe
    if ! id "$username" >/dev/null 2>&1; then
        log_action "ERREUR : L'utilisateur '$username' n'existe pas" "ERROR"
        return 1
    fi
    
    # Validation pré-suppression
    if ! pre_deletion_validation "$username"; then
        log_action "ERREUR : Validation pré-suppression échouée pour utilisateur : $username" "ERROR"
        return 1
    fi
    
    # Appliquer le processus de suppression basé sur politique
    apply_deletion_policy "$username" "$policy" "$compliance_framework" "$retention_period" "$authorized_by"
    
    # Générer le rapport de conformité
    generate_deletion_compliance_report "$username" "$policy" "$compliance_framework" "$authorized_by"
    
    log_action "Processus de suppression d'utilisateur d'entreprise terminé pour utilisateur : $username" "INFO"
}

# Validation pré-suppression et vérifications de sécurité
pre_deletion_validation() {
    local username="$1"
    
    echo "--- Validation Pré-Suppression ---"
    
    # Vérifier si l'utilisateur est un utilisateur système
    local user_id=$(id -u "$username" 2>/dev/null)
    if [[ $user_id -lt 500 ]]; then
        echo "✗ Impossible de supprimer l'utilisateur système (UID < 500) : $username"
        return 1
    fi
    
    # Vérifier si l'utilisateur est actuellement connecté
    if who | grep -q "^$username "; then
        echo "✗ L'utilisateur est actuellement connecté : $username"
        log_action "Suppression bloquée : L'utilisateur $username est actuellement connecté" "WARNING"
        return 1
    fi
    
    # Vérifier les exigences de jeton sécurisé
    local has_secure_token=$(sysadminctl -secureTokenStatus "$username" 2>/dev/null | grep -c "Enabled")
    if [[ $has_secure_token -eq 1 ]]; then
        local total_secure_tokens=$(sysadminctl -secureTokenStatus 2>/dev/null | grep -c "Enabled")
        if [[ $total_secure_tokens -eq 1 ]]; then
            echo "✗ Impossible de supprimer l'unique détenteur de jeton sécurisé : $username"
            log_action "Suppression bloquée : $username est l'unique détenteur de jeton sécurisé" "ERROR"
            return 1
        fi
    fi
    
    # Vérifier les processus actifs appartenant à l'utilisateur
    local user_processes=$(ps aux | awk -v user="$username" '$1 == user {print $2}' | wc -l | tr -d ' ')
    if [[ $user_processes -gt 0 ]]; then
        echo "⚠️ Avertissement : L'utilisateur a $user_processes processus actifs"
        echo "Arrêt des processus utilisateur..."
        pkill -u "$username" 2>/dev/null
        sleep 2
    fi
    
    # Vérifier la taille du répertoire personnel pour planification de sauvegarde
    local home_dir="/Users/$username"
    if [[ -d "$home_dir" ]]; then
        local dir_size=$(du -sm "$home_dir" 2>/dev/null | awk '{print $1}')
        echo "✓ Taille du répertoire personnel : ${dir_size}MB"
        
        # Vérifier l'espace disque disponible pour sauvegarde
        local available_space=$(df -m "$BACKUP_DIR" | tail -1 | awk '{print $4}')
        if [[ $dir_size -gt $available_space ]]; then
            echo "⚠️ Avertissement : Espace insuffisant pour sauvegarde"
            echo "Requis : ${dir_size}MB, Disponible : ${available_space}MB"
        fi
    fi
    
    echo "✓ Validation pré-suppression terminée"
    return 0
}

# Appliquer la politique de suppression
apply_deletion_policy() {
    local username="$1"
    local policy="$2"
    local compliance_framework="$3"
    local retention_period="$4"
    local authorized_by="$5"
    
    echo "--- Application de la Politique de Suppression : $policy ---"
    
    # Obtenir les actions de politique
    local policy_actions="${LIFECYCLE_POLICIES[$policy]}"
    if [[ -z "$policy_actions" ]]; then
        log_action "ERREUR : Politique de suppression inconnue : $policy" "ERROR"
        return 1
    fi
    
    echo "Actions de politique : $policy_actions"
    
    # Exécuter les actions de politique
    IFS=',' read -ra ACTIONS <<< "$policy_actions"
    for action in "${ACTIONS[@]}"; do
        case "$action" in
            "backup_data")
                echo "Exécution : Sauvegarde des données utilisateur"
                backup_user_data_enterprise "$username" "$compliance_framework"
                ;;
            "delete_account")
                echo "Exécution : Suppression du compte utilisateur"
                delete_user_account_enterprise "$username"
                ;;
            "delete_data")
                echo "Exécution : Suppression des données utilisateur"
                delete_user_data_secure "$username"
                ;;
            "preserve_home")
                echo "Exécution : Préservation du répertoire personnel"
                preserve_user_data "$username"
                ;;
            "disable_account")
                echo "Exécution : Désactivation du compte utilisateur"
                disable_user_account "$username"
                ;;
            "audit_log")
                echo "Exécution : Création du journal d'audit"
                create_audit_log "$username" "$policy" "$authorized_by"
                ;;
            "compliance_report")
                echo "Exécution : Génération du rapport de conformité"
                # Sera traité séparément
                ;;
            *)
                echo "Action inconnue : $action"
                ;;
        esac
    done
}

# Sauvegarde d'entreprise avec chiffrement et conformité
backup_user_data_enterprise() {
    local username="$1"
    local compliance_framework="$2"
    
    echo "--- Sauvegarde de Données d'Entreprise ---"
    
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_name="${username}_enterprise_backup_${timestamp}"
    local backup_path="$BACKUP_DIR/$backup_name"
    
    # Créer la sauvegarde avec métadonnées
    mkdir -p "$backup_path"
    
    # Copier les données utilisateur
    local user_home="/Users/$username"
    if [[ -d "$user_home" ]]; then
        echo "Sauvegarde du répertoire personnel utilisateur..."
        tar -czf "$backup_path/home_directory.tar.gz" -C "/Users" "$username" 2>/dev/null
    fi
    
    # Sauvegarder les informations de compte utilisateur
    echo "Sauvegarde des métadonnées de compte..."
    dscl . read "/Users/$username" > "$backup_path/account_metadata.txt" 2>/dev/null
    
    # Créer le manifeste de sauvegarde
    cat > "$backup_path/backup_manifest.json" << EOF
{
    "backup_manifest": {
        "username": "$username",
        "backup_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "backup_type": "enterprise_offboarding",
        "compliance_framework": "$compliance_framework",
        "backup_location": "$backup_path",
        "files_included": [
            "home_directory.tar.gz",
            "account_metadata.txt",
            "backup_manifest.json"
        ],
        "backup_size": "$(du -sh "$backup_path" | awk '{print $1}')",
        "hostname": "$(hostname)",
        "authorized_by": "$(whoami)",
        "backup_integrity": "$(find "$backup_path" -type f -exec md5 {} \; | md5)"
    }
}
EOF
    
    # Appliquer les protections spécifiques à la conformité
    if [[ -n "$compliance_framework" ]]; then
        apply_compliance_protections "$backup_path" "$compliance_framework"
    fi
    
    echo "✓ Sauvegarde d'entreprise terminée : $backup_path"
    log_action "Sauvegarde d'entreprise créée pour utilisateur $username à $backup_path" "INFO"
}

# Suppression sécurisée avec exigences de conformité
delete_user_data_secure() {
    local username="$1"
    local user_home="/Users/$username"
    
    echo "--- Suppression Sécurisée des Données ---"
    
    if [[ -d "$user_home" ]]; then
        echo "Exécution de la suppression sécurisée des données utilisateur..."
        
        # Suppression sécurisée multi-passes (standard DoD 5220.22-M)
        if command -v gshred >/dev/null 2>&1; then
            echo "Utilisation de gshred pour suppression sécurisée..."
            find "$user_home" -type f -exec gshred -vfz -n 3 {} \; 2>/dev/null
        elif command -v shred >/dev/null 2>&1; then
            echo "Utilisation de shred pour suppression sécurisée..."
            find "$user_home" -type f -exec shred -vfz -n 3 {} \; 2>/dev/null
        else
            echo "Outils de suppression sécurisée non disponibles, utilisation suppression standard..."
        fi
        
        # Supprimer la structure de répertoire
        rm -rf "$user_home" 2>/dev/null
        
        echo "✓ Suppression sécurisée terminée"
        log_action "Suppression sécurisée terminée pour données utilisateur : $user_home" "INFO"
    else
        echo "Aucun répertoire personnel utilisateur trouvé : $user_home"
    fi
}

# Désactiver le compte utilisateur au lieu de la suppression
disable_user_account() {
    local username="$1"
    
    echo "--- Désactivation du Compte Utilisateur ---"
    
    # Désactiver le compte avec dscl
    if dscl . create "/Users/$username" AuthenticationAuthority ";DisabledUser;" 2>/dev/null; then
        echo "✓ Compte utilisateur désactivé : $username"
        log_action "Compte utilisateur désactivé : $username" "INFO"
    else
        echo "✗ Échec de désactivation du compte utilisateur : $username"
        log_action "Échec de désactivation du compte utilisateur : $username" "ERROR"
    fi
    
    # Définir le shell de compte à /usr/bin/false
    dscl . create "/Users/$username" UserShell "/usr/bin/false" 2>/dev/null
    
    # Verrouiller le répertoire personnel
    local user_home="/Users/$username"
    if [[ -d "$user_home" ]]; then
        chmod 000 "$user_home" 2>/dev/null
        echo "✓ Accès au répertoire personnel révoqué"
    fi
}

# Générer un rapport de conformité complet
generate_deletion_compliance_report() {
    local username="$1"
    local policy="$2"
    local compliance_framework="$3"
    local authorized_by="$4"
    
    local report_file="$REPORT_DIR/user_deletion_report_${username}_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$report_file" << EOF
{
    "user_deletion_compliance_report": {
        "report_metadata": {
            "report_id": "$(uuidgen)",
            "generated_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
            "report_type": "user_account_deletion",
            "compliance_framework": "$compliance_framework",
            "hostname": "$(hostname)",
            "script_version": "$SCRIPT_VERSION"
        },
        "user_information": {
            "username": "$username",
            "deletion_policy": "$policy",
            "authorized_by": "$authorized_by",
            "deletion_timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
        },
        "compliance_details": {
            "framework": "$compliance_framework",
            "data_retention_requirements": "$(echo "${RETENTION_PERIODS[medium_term]}" | sed 's/indefinite/Rétention légale - rétention indéfinie/')",
            "secure_deletion_method": "Standard DoD 5220.22-M",
            "backup_location": "$BACKUP_DIR",
            "audit_trail": "$LOG_FILE"
        },
        "system_information": {
            "os_version": "$(sw_vers -productVersion)",
            "hardware_model": "$(system_profiler SPHardwareDataType | grep 'Model Identifier' | awk '{print $3}')",
            "secure_token_holders": $(sysadminctl -secureTokenStatus 2>/dev/null | grep -c "Enabled")
        }
    }
}
EOF
    
    echo "Rapport de conformité généré : $report_file"
    log_action "Rapport de conformité généré : $report_file" "INFO"
}

# Opérations de gestion d'utilisateurs de flotte
manage_fleet_users() {
    local operation="$1"
    local user_list="$2"
    local policy="${3:-secure_archival}"
    local compliance_framework="${4:-}"
    
    echo "=== Gestion d'Utilisateurs de Flotte ==="
    echo "Opération : $operation"
    echo "Politique : $policy"
    echo "Cadre de Conformité : $compliance_framework"
    echo ""
    
    case "$operation" in
        "bulk_delete")
            echo "Traitement de suppression d'utilisateurs en lot..."
            IFS=',' read -ra USERS <<< "$user_list"
            for username in "${USERS[@]}"; do
                echo "Traitement de l'utilisateur : $username"
                enterprise_user_deletion "$username" "$policy" "$compliance_framework"
                echo ""
            done
            ;;
        "audit_all")
            echo "Audit de tous les comptes utilisateur..."
            audit_all_users
            ;;
        "compliance_check")
            echo "Exécution de vérification de conformité..."
            compliance_check_users "$compliance_framework"
            ;;
        *)
            echo "Opération inconnue : $operation"
            return 1
            ;;
    esac
}

# Fonction d'exécution principale
main() {
    local action="${1:-help}"
    local param1="${2:-}"
    local param2="${3:-}"
    local param3="${4:-}"
    local param4="${5:-}"
    local param5="${6:-}"
    
    log_action "=== Gestion du Cycle de Vie Utilisateur MacFleet Démarrée ===" "INFO"
    log_action "Action : $action" "INFO"
    
    case "$action" in
        "delete")
            if [[ -z "$param1" ]]; then
                echo "Usage : $0 delete <nom_utilisateur> [politique] [cadre_conformité] [période_rétention] [autorisé_par]"
                echo "Politiques : ${!LIFECYCLE_POLICIES[*]}"
                echo "Conformité : ${!COMPLIANCE_FRAMEWORKS[*]}"
                echo "Rétention : ${!RETENTION_PERIODS[*]}"
                exit 1
            fi
            enterprise_user_deletion "$param1" "$param2" "$param3" "$param4" "$param5"
            ;;
        "backup")
            if [[ -z "$param1" ]]; then
                echo "Usage : $0 backup <nom_utilisateur> [cadre_conformité]"
                exit 1
            fi
            backup_user_data_enterprise "$param1" "$param2"
            ;;
        "disable")
            if [[ -z "$param1" ]]; then
                echo "Usage : $0 disable <nom_utilisateur>"
                exit 1
            fi
            disable_user_account "$param1"
            ;;
        "fleet")
            if [[ -z "$param1" || -z "$param2" ]]; then
                echo "Usage : $0 fleet <opération> <liste_utilisateurs> [politique] [cadre_conformité]"
                echo "Opérations : bulk_delete, audit_all, compliance_check"
                exit 1
            fi
            manage_fleet_users "$param1" "$param2" "$param3" "$param4"
            ;;
        "validate")
            if [[ -z "$param1" ]]; then
                echo "Usage : $0 validate <nom_utilisateur>"
                exit 1
            fi
            pre_deletion_validation "$param1"
            ;;
        "prereq")
            check_deletion_prerequisites
            ;;
        "help")
            echo "Usage : $0 [action] [options...]"
            echo "Actions :"
            echo "  delete <nom_utilisateur> [politique] [conformité] [rétention] [autorisé_par] - Supprimer utilisateur avec politiques d'entreprise"
            echo "  backup <nom_utilisateur> [conformité] - Sauvegarder données utilisateur"
            echo "  disable <nom_utilisateur> - Désactiver compte utilisateur"
            echo "  fleet <opération> <liste_utilisateurs> [politique] [conformité] - Opérations utilisateurs de flotte"
            echo "  validate <nom_utilisateur> - Valider prérequis suppression"
            echo "  prereq - Vérifier prérequis système"
            echo "  help - Afficher cette aide"
            echo ""
            echo "Politiques : ${!LIFECYCLE_POLICIES[*]}"
            echo "Conformité : ${!COMPLIANCE_FRAMEWORKS[*]}"
            echo "Rétention : ${!RETENTION_PERIODS[*]}"
            ;;
        *)
            log_action "ERREUR : Action inconnue : $action" "ERROR"
            echo "Utilisez '$0 help' pour les informations d'utilisation"
            exit 1
            ;;
    esac
    
    log_action "=== Gestion du cycle de vie utilisateur terminée ===" "INFO"
}

# Exécuter la fonction principale
main "$@"

Considérations de Sécurité Importantes

Exigences de Jeton Sécurisé

#!/bin/bash

# Gérer les exigences de jeton sécurisé pour suppression d'utilisateur
manage_secure_tokens() {
    echo "=== Gestion des Jetons Sécurisés ==="
    
    # Lister tous les détenteurs de jeton sécurisé
    echo "Détenteurs de jeton sécurisé actuels :"
    sysadminctl -secureTokenStatus 2>/dev/null | grep -E "(Username|Enabled)"
    
    echo ""
    echo "--- Directives Jeton Sécurisé ---"
    echo "1. Impossible de supprimer l'unique détenteur de jeton sécurisé"
    echo "2. Doit avoir au moins un admin avec jeton sécurisé"
    echo "3. Accorder jeton sécurisé avant tentative de suppression"
    echo "4. Jeton sécurisé requis pour FileVault et certaines opérations"
}

# Accorder jeton sécurisé à utilisateur admin
grant_secure_token() {
    local admin_user="$1"
    local target_user="$2"
    
    if [[ -z "$admin_user" || -z "$target_user" ]]; then
        echo "Usage : grant_secure_token <utilisateur_admin> <utilisateur_cible>"
        return 1
    fi
    
    echo "Accord de jeton sécurisé à $target_user via $admin_user..."
    sysadminctl -secureTokenOn "$target_user" -password -adminUser "$admin_user"
}

# Usage
manage_secure_tokens

Rétention des Données et Conformité

#!/bin/bash

# Implémenter les politiques de rétention des données
implement_retention_policy() {
    local policy_name="$1"
    local retention_days="${2:-90}"
    
    echo "=== Implémentation de Politique de Rétention des Données ==="
    echo "Politique : $policy_name"
    echo "Période de Rétention : $retention_days jours"
    
    # Trouver les anciennes sauvegardes pour nettoyage
    local old_backups=$(find "$BACKUP_DIR" -type d -mtime +$retention_days 2>/dev/null)
    
    if [[ -n "$old_backups" ]]; then
        echo "Sauvegardes trouvées plus anciennes que $retention_days jours :"
        echo "$old_backups"
        
        # Archiver les anciennes sauvegardes avant suppression (si requis par politique)
        case "$policy_name" in
            "legal_hold")
                echo "Rétention légale active - aucune suppression effectuée"
                ;;
            "compliance_minimum")
                echo "Rétention minimum de conformité - archivage vers stockage long terme"
                ;;
            *)
                echo "Rétention standard - marquage pour suppression"
                ;;
        esac
    else
        echo "Aucune sauvegarde trouvée plus ancienne que $retention_days jours"
    fi
}

# Usage
implement_retention_policy "standard" "90"

Notes Importantes

  • Privilèges Administrateur - La suppression d'utilisateur nécessite des privilèges administrateur et une authentification appropriée
  • Gestion de Jeton Sécurisé - Impossible de supprimer l'unique détenteur de jeton sécurisé ; s'assurer que plusieurs utilisateurs admin existent
  • Accès Disque Complet - L'app Service nécessite la permission Accès Disque Complet dans Préférences Système
  • Sauvegarde des Données - Toujours sauvegarder les données utilisateur avant suppression si requis par les politiques organisationnelles
  • Exigences de Conformité - Différentes industries ont des exigences spécifiques de rétention et suppression des données
  • Pistes d'Audit - Maintenir des journaux complets de toutes les activités de suppression d'utilisateur pour conformité
  • Procédures de Récupération - Tester les procédures de sauvegarde et récupération avant d'implémenter les politiques de suppression

Gestion Entreprise des Fuseaux Horaires sur macOS

Gérez les fuseaux horaires et les paramètres de date/heure dans votre MacFleet avec automation de niveau entreprise, politiques de conformité géographique et capacités de surveillance complètes.

Comprendre la Gestion Entreprise des Fuseaux Horaires

La gestion des fuseaux horaires en entreprise nécessite plus qu'un simple réglage de l'heure, exigeant :

  • Conformité géographique automatisée avec politiques de fuseaux horaires régionales
  • Synchronisation temporelle centralisée avec serveurs NTP d'entreprise
  • Application de politiques pour les heures d'ouverture et conformité opérationnelle
  • Surveillance en temps réel de la dérive temporelle et du statut de synchronisation
  • Journalisation d'audit pour les exigences de conformité et sécurité
  • Capacités d'intégration avec l'infrastructure et services d'annuaire existants

Processus de Base de Gestion des Fuseaux Horaires

Commandes de Base

  1. Définir Fuseau Horaire - sudo systemsetup -settimezone <timezone>
  2. Lister Fuseaux Horaires - sudo systemsetup -listtimezones
  3. Activer Heure Réseau - /usr/sbin/systemsetup -setusingnetworktime on
  4. Définir Serveur Temps - /usr/sbin/systemsetup -setnetworktimeserver time.apple.com

Exemples de Configuration de Base

# Réglage de fuseau horaire de base
sudo systemsetup -settimezone Pacific/Ponape

# Activer la synchronisation automatique de l'heure
/usr/sbin/systemsetup -setusingnetworktime on -setnetworktimeserver time.apple.com

# Lister les fuseaux horaires disponibles
sudo systemsetup -listtimezones

Système de Gestion des Fuseaux Horaires Entreprise

#!/bin/bash

# Système de Gestion des Fuseaux Horaires Entreprise MacFleet
# Gestion complète des fuseaux horaires et date/heure avec contrôles entreprise et surveillance

# Configuration
SCRIPT_NAME="Gestionnaire Fuseau Horaire MacFleet"
VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_timezone.log"
AUDIT_LOG="/var/log/macfleet_timezone_audit.log"
CONFIG_DIR="/etc/macfleet/timezone"
POLICIES_DIR="/etc/macfleet/timezone/policies"
BACKUP_DIR="/var/backups/timezone"
TEMP_DIR="/tmp/macfleet_timezone"
TIME_DRIFT_THRESHOLD=30  # secondes
SYNC_CHECK_INTERVAL=300  # 5 minutes
ORGANIZATION_NAME="MacFleet Entreprise"
DEPLOYMENT_MODE="enterprise"
ENABLE_COMPLIANCE_CHECKING=true
ENABLE_GEOGRAPHIC_POLICIES=true
AUTO_TIME_SYNC=true

# Serveurs de Temps Entreprise (par ordre de priorité)
declare -a ENTERPRISE_TIME_SERVERS=(
    "time.company.com"          # Serveur NTP entreprise principal
    "time2.company.com"         # Serveur NTP entreprise secondaire
    "time.apple.com"            # Serveur temps Apple (fallback)
    "pool.ntp.org"              # Pool NTP public (fallback)
    "time.nist.gov"             # Serveur temps NIST (fallback)
)

# Mapping Politique Géographique
declare -A GEOGRAPHIC_POLICIES=(
    ["US_EAST"]="America/New_York"
    ["US_CENTRAL"]="America/Chicago"
    ["US_MOUNTAIN"]="America/Denver"
    ["US_PACIFIC"]="America/Los_Angeles"
    ["US_ALASKA"]="America/Anchorage"
    ["US_HAWAII"]="Pacific/Honolulu"
    ["EU_LONDON"]="Europe/London"
    ["EU_PARIS"]="Europe/Paris"
    ["EU_BERLIN"]="Europe/Berlin"
    ["EU_ZURICH"]="Europe/Zurich"
    ["ASIA_TOKYO"]="Asia/Tokyo"
    ["ASIA_SINGAPORE"]="Asia/Singapore"
    ["ASIA_HONG_KONG"]="Asia/Hong_Kong"
    ["AUSTRALIA_SYDNEY"]="Australia/Sydney"
)

# Politiques Heures d'Ouverture
declare -A BUSINESS_HOURS_POLICIES=(
    ["standard"]="09:00-17:00"
    ["extended"]="08:00-18:00"
    ["24x7"]="00:00-23:59"
    ["custom"]="configurable"
)

# Exigences de Conformité
declare -A COMPLIANCE_STANDARDS=(
    ["SOX"]="audit_temps_strict"
    ["HIPAA"]="journalisation_synchronisee"
    ["PCI_DSS"]="sync_temps_securise"
    ["ISO27001"]="validation_source_temps"
)

# Créer les répertoires nécessaires
mkdir -p "$CONFIG_DIR"
mkdir -p "$POLICIES_DIR"
mkdir -p "$BACKUP_DIR"
mkdir -p "$TEMP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$(dirname "$AUDIT_LOG")"

# Définir les permissions sécurisées
chmod 755 "$CONFIG_DIR"
chmod 750 "$POLICIES_DIR"
chmod 750 "$BACKUP_DIR"
chmod 700 "$TEMP_DIR"

# Fonctions de journalisation
log_operation() {
    local level="$1"
    local message="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local admin_user=$(whoami)
    echo "[$timestamp] [$level] [$admin_user] $message" | tee -a "$LOG_FILE"
}

log_security_event() {
    local event_type="$1"
    local details="$2"
    local severity="$3"
    local admin_user=$(whoami)
    
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local source_ip=$(who am i | awk '{print $5}' | tr -d '()')
    echo "SECURITY|$timestamp|$event_type|$severity|$admin_user|$source_ip|$details" >> "$AUDIT_LOG"
}

# Obtenir les informations actuelles du fuseau horaire
get_current_timezone() {
    local current_tz=$(systemsetup -gettimezone 2>/dev/null | awk -F': ' '{print $2}')
    local current_time=$(date '+%Y-%m-%d %H:%M:%S %Z')
    local utc_time=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
    local time_server=$(systemsetup -getnetworktimeserver 2>/dev/null | awk -F': ' '{print $2}')
    local network_time_status=$(systemsetup -getusingnetworktime 2>/dev/null | awk -F': ' '{print $2}')
    
    echo "=== Informations Fuseau Horaire Actuel ==="
    echo "Fuseau Horaire : $current_tz"
    echo "Heure Locale : $current_time"
    echo "Heure UTC : $utc_time"
    echo "Serveur Temps : $time_server"
    echo "Sync Heure Réseau : $network_time_status"
    echo ""
}

# Lister les fuseaux horaires disponibles avec groupement géographique
list_available_timezones() {
    local filter_region="${1:-all}"
    local format="${2:-grouped}"
    
    echo "=== Fuseaux Horaires Disponibles ==="
    echo "Filtre : $filter_region"
    echo "Format : $format"
    echo ""
    
    if [[ "$format" == "grouped" ]]; then
        # Grouper par région
        echo "Amériques :"
        systemsetup -listtimezones 2>/dev/null | grep "America/" | sort | head -20
        echo ""
        
        echo "Europe :"
        systemsetup -listtimezones 2>/dev/null | grep "Europe/" | sort | head -20
        echo ""
        
        echo "Asie :"
        systemsetup -listtimezones 2>/dev/null | grep "Asia/" | sort | head -20
        echo ""
        
        echo "Pacifique :"
        systemsetup -listtimezones 2>/dev/null | grep "Pacific/" | sort | head -20
        echo ""
        
        echo "Autres :"
        systemsetup -listtimezones 2>/dev/null | grep -v -E "America/|Europe/|Asia/|Pacific/" | sort | head -10
    else
        # Liste simple
        case "$filter_region" in
            "americas"|"america")
                systemsetup -listtimezones 2>/dev/null | grep "America/" | sort
                ;;
            "europe")
                systemsetup -listtimezones 2>/dev/null | grep "Europe/" | sort
                ;;
            "asia")
                systemsetup -listtimezones 2>/dev/null | grep "Asia/" | sort
                ;;
            "pacific")
                systemsetup -listtimezones 2>/dev/null | grep "Pacific/" | sort
                ;;
            *)
                systemsetup -listtimezones 2>/dev/null | sort
                ;;
        esac
    fi
}

# Valider le fuseau horaire
validate_timezone() {
    local timezone="$1"
    
    if [[ -z "$timezone" ]]; then
        echo "Erreur : Le fuseau horaire ne peut pas être vide"
        return 1
    fi
    
    # Vérifier si le fuseau horaire existe dans la liste système
    if systemsetup -listtimezones 2>/dev/null | grep -q "^$timezone$"; then
        echo "✅ Fuseau horaire '$timezone' est valide"
        return 0
    else
        echo "❌ Fuseau horaire '$timezone' n'est pas valide"
        echo "Utilisez la commande 'list-timezones' pour voir les options disponibles"
        return 1
    fi
}

# Définir le fuseau horaire avec validation entreprise
set_enterprise_timezone() {
    local timezone="$1"
    local policy="${2:-standard}"
    local force="${3:-false}"
    local admin_user=$(whoami)
    
    log_security_event "TIMEZONE_CHANGE_ATTEMPT" "timezone=$timezone,policy=$policy" "INFO"
    
    echo "=== Configuration Fuseau Horaire Entreprise ==="
    echo "Fuseau Horaire Cible : $timezone"
    echo "Politique : $policy"
    echo "Administrateur : $admin_user"
    echo "Mode Force : $force"
    echo ""
    
    # Valider le fuseau horaire
    if ! validate_timezone "$timezone"; then
        log_operation "ERROR" "Fuseau horaire invalide spécifié : $timezone"
        return 1
    fi
    
    # Vérifier le fuseau horaire actuel
    local current_tz=$(systemsetup -gettimezone 2>/dev/null | awk -F': ' '{print $2}')
    
    if [[ "$current_tz" == "$timezone" && "$force" != "true" ]]; then
        echo "✅ Fuseau horaire déjà défini sur $timezone"
        log_operation "INFO" "Fuseau horaire inchangé : $timezone"
        return 0
    fi
    
    # Sauvegarder la configuration actuelle
    local backup_file="$BACKUP_DIR/timezone_$(date +%Y%m%d_%H%M%S).conf"
    {
        echo "# Sauvegarde Fuseau Horaire MacFleet"
        echo "PREVIOUS_TIMEZONE=$current_tz"
        echo "PREVIOUS_TIME_SERVER=$(systemsetup -getnetworktimeserver 2>/dev/null | awk -F': ' '{print $2}')"
        echo "PREVIOUS_NETWORK_TIME=$(systemsetup -getusingnetworktime 2>/dev/null | awk -F': ' '{print $2}')"
        echo "BACKUP_TIMESTAMP=$(date)"
        echo "CHANGED_BY=$admin_user"
    } > "$backup_file"
    
    log_operation "INFO" "Configuration sauvegardée dans : $backup_file"
    
    # Appliquer le changement de fuseau horaire
    echo "Définition du fuseau horaire sur : $timezone"
    
    if sudo systemsetup -settimezone "$timezone" 2>/dev/null; then
        echo "✅ Fuseau horaire défini avec succès"
        log_operation "INFO" "Fuseau horaire changé de '$current_tz' vers '$timezone'"
        log_security_event "TIMEZONE_CHANGED" "from=$current_tz,to=$timezone,policy=$policy" "INFO"
        
        # Configurer la synchronisation de l'heure réseau
        configure_time_sync "$policy"
        
        # Vérifier le changement
        sleep 2
        local new_tz=$(systemsetup -gettimezone 2>/dev/null | awk -F': ' '{print $2}')
        
        if [[ "$new_tz" == "$timezone" ]]; then
            echo "✅ Vérification du fuseau horaire réussie"
            
            # Afficher les informations de temps mises à jour
            get_current_timezone
            
            return 0
        else
            echo "❌ Vérification du fuseau horaire échouée"
            log_operation "ERROR" "Vérification fuseau horaire échouée : attendu '$timezone', obtenu '$new_tz'"
            return 1
        fi
    else
        echo "❌ Échec de définition du fuseau horaire"
        log_operation "ERROR" "Échec de définition du fuseau horaire sur : $timezone"
        log_security_event "TIMEZONE_CHANGE_FAILED" "timezone=$timezone,error=systemsetup_failed" "ERROR"
        return 1
    fi
}

# Configurer la synchronisation de l'heure
configure_time_sync() {
    local policy="${1:-standard}"
    local admin_user=$(whoami)
    
    echo "=== Configuration Synchronisation Heure ==="
    echo "Politique : $policy"
    echo ""
    
    # Déterminer le serveur de temps basé sur la politique
    local time_server
    case "$policy" in
        "enterprise")
            time_server="${ENTERPRISE_TIME_SERVERS[0]}"
            ;;
        "secure")
            time_server="${ENTERPRISE_TIME_SERVERS[1]}"
            ;;
        "standard")
            time_server="time.apple.com"
            ;;
        "public")
            time_server="pool.ntp.org"
            ;;
        *)
            time_server="time.apple.com"
            ;;
    esac
    
    echo "Définition du serveur de temps sur : $time_server"
    
    # Activer l'heure réseau et définir le serveur
    if sudo systemsetup -setusingnetworktime on -setnetworktimeserver "$time_server" 2>/dev/null; then
        echo "✅ Synchronisation de l'heure configurée avec succès"
        log_operation "INFO" "Sync temps configuré : serveur=$time_server, politique=$policy"
        
        # Tester la connectivité du serveur de temps
        test_time_server_connectivity "$time_server"
        
        return 0
    else
        echo "❌ Échec de configuration de la synchronisation de l'heure"
        log_operation "ERROR" "Échec config sync temps : serveur=$time_server"
        
        # Essayer les serveurs de fallback
        echo "Tentative de serveurs de temps de fallback..."
        for fallback_server in "${ENTERPRISE_TIME_SERVERS[@]}"; do
            if [[ "$fallback_server" != "$time_server" ]]; then
                echo "Tentative serveur fallback : $fallback_server"
                
                if sudo systemsetup -setusingnetworktime on -setnetworktimeserver "$fallback_server" 2>/dev/null; then
                    echo "✅ Serveur de temps fallback configuré : $fallback_server"
                    log_operation "INFO" "Sync temps fallback configuré : $fallback_server"
                    return 0
                fi
            fi
        done
        
        echo "❌ Toutes les configurations de serveur de temps ont échoué"
        log_operation "ERROR" "Toutes les configurations de serveur de temps ont échoué"
        return 1
    fi
}

# Tester la connectivité du serveur de temps
test_time_server_connectivity() {
    local time_server="$1"
    local timeout=10
    
    echo "Test de connectivité vers le serveur de temps : $time_server"
    
    # Tester la connectivité de base
    if timeout "$timeout" ping -c 3 "$time_server" &>/dev/null; then
        echo "✅ Serveur de temps accessible"
        
        # Tester la connectivité NTP spécifique (si ntpdate est disponible)
        if command -v ntpdate &>/dev/null; then
            if timeout "$timeout" ntpdate -q "$time_server" &>/dev/null; then
                echo "✅ Service NTP répond"
                return 0
            else
                echo "⚠️  Serveur de temps accessible mais NTP peut ne pas répondre"
                return 1
            fi
        else
            echo "✅ Connectivité de base confirmée (ntpdate non disponible pour test NTP)"
            return 0
        fi
    else
        echo "❌ Serveur de temps non accessible"
        log_operation "WARNING" "Connectivité serveur de temps échouée : $time_server"
        return 1
    fi
}

# Surveiller la dérive temporelle et la synchronisation
monitor_time_sync() {
    local check_type="${1:-basic}"
    local admin_user=$(whoami)
    
    echo "=== Surveillance Synchronisation Heure ==="
    echo "Type de Vérification : $check_type"
    echo "Surveillant : $admin_user"
    echo ""
    
    local sync_status="HEALTHY"
    local issues=()
    
    # Vérifier si l'heure réseau est activée
    local network_time_status=$(systemsetup -getusingnetworktime 2>/dev/null | awk -F': ' '{print $2}')
    
    if [[ "$network_time_status" == "On" ]]; then
        echo "✅ Synchronisation heure réseau activée"
    else
        echo "❌ Synchronisation heure réseau désactivée"
        sync_status="CRITICAL"
        issues+=("Sync heure réseau désactivée")
    fi
    
    # Vérifier la configuration du serveur de temps
    local time_server=$(systemsetup -getnetworktimeserver 2>/dev/null | awk -F': ' '{print $2}')
    echo "Serveur de Temps : $time_server"
    
    # Tester la connectivité du serveur de temps
    if ! test_time_server_connectivity "$time_server"; then
        sync_status="WARNING"
        issues+=("Problèmes de connectivité serveur de temps")
    fi
    
    # Vérifier la dérive temporelle (si ntpdate est disponible)
    if command -v ntpdate &>/dev/null; then
        echo ""
        echo "Vérification de la dérive temporelle..."
        
        local drift_output=$(ntpdate -q "$time_server" 2>/dev/null | tail -1)
        
        if [[ -n "$drift_output" ]]; then
            # Extraire la valeur de dérive (analyse simplifiée)
            local drift_seconds=$(echo "$drift_output" | grep -o "offset [+-][0-9.]*" | awk '{print $2}' | tr -d '+')
            
            if [[ -n "$drift_seconds" ]]; then
                local drift_abs=$(echo "$drift_seconds" | tr -d '-')
                
                echo "Dérive temporelle : ${drift_seconds}s"
                
                if (( $(echo "$drift_abs > $TIME_DRIFT_THRESHOLD" | bc -l) )); then
                    echo "⚠️  Dérive temporelle dépasse le seuil (${TIME_DRIFT_THRESHOLD}s)"
                    sync_status="WARNING"
                    issues+=("Dérive temporelle : ${drift_seconds}s")
                else
                    echo "✅ Dérive temporelle dans la plage acceptable"
                fi
            fi
        fi
    else
        echo "ntpdate non disponible pour vérification de dérive"
    fi
    
    # Vérifications avancées
    if [[ "$check_type" == "comprehensive" ]]; then
        echo ""
        echo "Exécution surveillance temps complète..."
        
        # Vérifier horloge système vs horloge matérielle
        if command -v hwclock &>/dev/null; then
            local sys_time=$(date +%s)
            local hw_time=$(sudo hwclock --show | date -f - +%s 2>/dev/null || echo "0")
            
            if [[ "$hw_time" != "0" ]]; then
                local clock_diff=$((sys_time - hw_time))
                local clock_diff_abs=${clock_diff#-}
                
                echo "Différence horloge système/matérielle : ${clock_diff}s"
                
                if [[ $clock_diff_abs -gt 30 ]]; then
                    sync_status="WARNING"
                    issues+=("Dérive horloge système/matérielle : ${clock_diff}s")
                fi
            fi
        fi
        
        # Vérifier les processus chronyd ou ntpd
        if pgrep -x "chronyd" &>/dev/null || pgrep -x "ntpd" &>/dev/null; then
            echo "✅ Démon de temps en cours d'exécution"
        else
            echo "⚠️  Aucun démon de temps détecté"
        fi
    fi
    
    # Générer le rapport de surveillance
    echo ""
    echo "=== Rapport État Sync Temps ==="
    echo "État Global : $sync_status"
    echo "Horodatage : $(date)"
    
    if [[ ${#issues[@]} -gt 0 ]]; then
        echo "Problèmes Trouvés :"
        printf '  - %s\n' "${issues[@]}"
    else
        echo "✅ Tous les systèmes de synchronisation temporelle opérationnels"
    fi
    
    # Enregistrer les résultats de surveillance
    log_operation "INFO" "Surveillance sync temps terminée : $sync_status (${#issues[@]} problèmes)"
    log_security_event "TIME_SYNC_CHECK" "status=$sync_status,issues=${#issues[@]}" "INFO"
    
    # Retourner le code de sortie approprié
    case "$sync_status" in
        "HEALTHY") return 0 ;;
        "WARNING") return 1 ;;
        "CRITICAL") return 2 ;;
        *) return 3 ;;
    esac
}

# Appliquer une politique géographique
apply_geographic_policy() {
    local policy_name="$1"
    local admin_user=$(whoami)
    
    log_security_event "GEOGRAPHIC_POLICY_APPLY" "policy=$policy_name" "INFO"
    
    echo "=== Application Politique Géographique ==="
    echo "Politique : $policy_name"
    echo "Administrateur : $admin_user"
    echo ""
    
    # Vérifier si la politique existe
    if [[ -z "${GEOGRAPHIC_POLICIES[$policy_name]}" ]]; then
        echo "❌ Politique géographique inconnue : $policy_name"
        echo ""
        echo "Politiques disponibles :"
        for policy in "${!GEOGRAPHIC_POLICIES[@]}"; do
            echo "  $policy -> ${GEOGRAPHIC_POLICIES[$policy]}"
        done
        return 1
    fi
    
    local target_timezone="${GEOGRAPHIC_POLICIES[$policy_name]}"
    
    echo "Fuseau horaire cible : $target_timezone"
    echo "Mapping politique : $policy_name -> $target_timezone"
    echo ""
    
    # Appliquer le changement de fuseau horaire
    set_enterprise_timezone "$target_timezone" "geographic_policy"
}

# Générer un rapport de conformité des fuseaux horaires
generate_timezone_report() {
    local report_type="${1:-summary}"
    local admin_user=$(whoami)
    local report_file="/var/reports/timezone_report_$(date +%Y%m%d_%H%M%S).txt"
    
    mkdir -p "$(dirname "$report_file")"
    
    log_security_event "REPORT_GENERATION" "type=$report_type" "INFO"
    
    {
        echo "Rapport Gestion Fuseau Horaire MacFleet"
        echo "======================================"
        echo "Type de Rapport : $report_type"
        echo "Généré : $(date)"
        echo "Généré Par : $admin_user"
        echo "Nom d'hôte : $(hostname)"
        echo ""
        
        case "$report_type" in
            "summary")
                echo "== Résumé Fuseau Horaire =="
                get_current_timezone
                
                echo "Politiques Géographiques Disponibles :"
                for policy in "${!GEOGRAPHIC_POLICIES[@]}"; do
                    echo "  $policy: ${GEOGRAPHIC_POLICIES[$policy]}"
                done
                ;;
            "compliance")
                echo "== Évaluation Conformité =="
                
                # Vérifier les exigences de conformité
                local current_tz=$(systemsetup -gettimezone 2>/dev/null | awk -F': ' '{print $2}')
                local network_time=$(systemsetup -getusingnetworktime 2>/dev/null | awk -F': ' '{print $2}')
                local time_server=$(systemsetup -getnetworktimeserver 2>/dev/null | awk -F': ' '{print $2}')
                
                echo "Configuration Actuelle :"
                echo "  Fuseau Horaire : $current_tz"
                echo "  Sync Heure Réseau : $network_time"
                echo "  Serveur Temps : $time_server"
                echo ""
                
                echo "Standards de Conformité :"
                for standard in "${!COMPLIANCE_STANDARDS[@]}"; do
                    echo "  $standard: ${COMPLIANCE_STANDARDS[$standard]}"
                done
                ;;
            "audit")
                echo "== Information d'Audit =="
                if [[ -f "$AUDIT_LOG" ]]; then
                    echo "Événements fuseau horaire récents (20 derniers) :"
                    tail -20 "$AUDIT_LOG"
                else
                    echo "Aucun log d'audit disponible"
                fi
                ;;
        esac
        
        echo ""
        echo "== Informations Temps Système =="
        echo "Heure Locale : $(date)"
        echo "Heure UTC : $(date -u)"
        echo "Uptime : $(uptime)"
        
    } > "$report_file"
    
    echo "Rapport fuseau horaire généré : $report_file"
    log_operation "INFO" "Rapport fuseau horaire généré : $report_file"
}

# Définir une politique d'heures d'ouverture
set_business_hours_policy() {
    local policy_name="$1"
    local custom_hours="$2"
    
    echo "=== Configuration Politique Heures d'Ouverture ==="
    echo "Politique : $policy_name"
    
    if [[ "$policy_name" == "custom" && -n "$custom_hours" ]]; then
        echo "Heures Personnalisées : $custom_hours"
        BUSINESS_HOURS_POLICIES["custom"]="$custom_hours"
    fi
    
    local hours="${BUSINESS_HOURS_POLICIES[$policy_name]}"
    
    if [[ -z "$hours" ]]; then
        echo "❌ Politique heures d'ouverture inconnue : $policy_name"
        echo ""
        echo "Politiques disponibles :"
        for policy in "${!BUSINESS_HOURS_POLICIES[@]}"; do
            echo "  $policy: ${BUSINESS_HOURS_POLICIES[$policy]}"
        done
        return 1
    fi
    
    echo "Heures d'Ouverture : $hours"
    
    # Sauvegarder la politique dans le fichier de configuration
    local policy_file="$POLICIES_DIR/business_hours.conf"
    {
        echo "# Politique Heures d'Ouverture MacFleet"
        echo "POLICY_NAME=$policy_name"
        echo "BUSINESS_HOURS=$hours"
        echo "CONFIGURED_BY=$(whoami)"
        echo "CONFIGURED_DATE=$(date)"
    } > "$policy_file"
    
    echo "✅ Politique heures d'ouverture configurée"
    log_operation "INFO" "Politique heures d'ouverture définie : $policy_name ($hours)"
}

# Fonction principale de gestion des fuseaux horaires
main() {
    local action="${1:-help}"
    
    case "$action" in
        "status"|"current")
            get_current_timezone
            ;;
        "list-timezones")
            local filter_region="$2"
            local format="${3:-grouped}"
            
            list_available_timezones "$filter_region" "$format"
            ;;
        "set")
            local timezone="$2"
            local policy="${3:-standard}"
            local force="$4"
            
            if [[ -z "$timezone" ]]; then
                echo "Usage : $0 set <timezone> [policy] [force]"
                echo "Exemple : $0 set America/New_York enterprise"
                return 1
            fi
            
            set_enterprise_timezone "$timezone" "$policy" "$force"
            ;;
        "validate")
            local timezone="$2"
            
            if [[ -z "$timezone" ]]; then
                echo "Usage : $0 validate <timezone>"
                return 1
            fi
            
            validate_timezone "$timezone"
            ;;
        "sync")
            local policy="${2:-standard}"
            
            configure_time_sync "$policy"
            ;;
        "monitor")
            local check_type="${2:-basic}"
            
            monitor_time_sync "$check_type"
            ;;
        "apply-policy")
            local policy_name="$2"
            
            if [[ -z "$policy_name" ]]; then
                echo "Usage : $0 apply-policy <policy_name>"
                echo ""
                echo "Politiques géographiques disponibles :"
                for policy in "${!GEOGRAPHIC_POLICIES[@]}"; do
                    echo "  $policy"
                done
                return 1
            fi
            
            apply_geographic_policy "$policy_name"
            ;;
        "business-hours")
            local policy_name="$2"
            local custom_hours="$3"
            
            if [[ -z "$policy_name" ]]; then
                echo "Usage : $0 business-hours <policy> [custom_hours]"
                echo ""
                echo "Politiques disponibles :"
                for policy in "${!BUSINESS_HOURS_POLICIES[@]}"; do
                    echo "  $policy"
                done
                return 1
            fi
            
            set_business_hours_policy "$policy_name" "$custom_hours"
            ;;
        "report")
            local report_type="${2:-summary}"
            
            generate_timezone_report "$report_type"
            ;;
        "help"|*)
            echo "$SCRIPT_NAME v$VERSION"
            echo "Gestion Entreprise des Fuseaux Horaires et Date/Heure"
            echo ""
            echo "Usage : $0 <action> [options]"
            echo ""
            echo "Actions :"
            echo "  status                                  - Afficher les informations fuseau horaire actuel"
            echo "  list-timezones [region] [format]        - Lister les fuseaux horaires disponibles"
            echo "  set <timezone> [policy] [force]         - Définir fuseau horaire avec politique"
            echo "  validate <timezone>                     - Valider le format du fuseau horaire"
            echo "  sync [policy]                           - Configurer la synchronisation de l'heure"
            echo "  monitor [type]                          - Surveiller la synchronisation de l'heure"
            echo "  apply-policy <policy>                   - Appliquer une politique géographique"
            echo "  business-hours <policy> [custom]        - Configurer les heures d'ouverture"
            echo "  report [type]                           - Générer des rapports de fuseau horaire"
            echo "  help                                    - Afficher ce message d'aide"
            echo ""
            echo "Politiques Géographiques :"
            for policy in "${!GEOGRAPHIC_POLICIES[@]}"; do
                echo "  $policy"
            done
            echo ""
            echo "Politiques Sync Temps :"
            echo "  enterprise  - Utiliser serveur NTP entreprise principal"
            echo "  secure      - Utiliser serveur NTP entreprise secondaire"
            echo "  standard    - Utiliser serveur temps Apple (défaut)"
            echo "  public      - Utiliser pool NTP public"
            echo ""
            echo "Politiques Heures d'Ouverture :"
            for policy in "${!BUSINESS_HOURS_POLICIES[@]}"; do
                echo "  $policy: ${BUSINESS_HOURS_POLICIES[$policy]}"
            done
            echo ""
            echo "Types de Surveillance :"
            echo "  basic       - Vérification statut sync temps de base"
            echo "  comprehensive - Surveillance étendue et diagnostics"
            echo ""
            echo "Types de Rapport :"
            echo "  summary     - Aperçu fuseau horaire (défaut)"
            echo "  compliance  - Évaluation conformité"
            echo "  audit       - Piste d'audit et événements"
            echo ""
            echo "Exemples :"
            echo "  $0 set America/New_York enterprise      - Définir heure Est avec politique entreprise"
            echo "  $0 apply-policy US_PACIFIC              - Appliquer politique Pacifique US"
            echo "  $0 monitor comprehensive                - Vérification surveillance complète"
            echo "  $0 business-hours extended              - Définir heures ouverture étendues"
            echo ""
            echo "Fonctionnalités :"
            echo "  • Gestion fuseaux horaires niveau entreprise"
            echo "  • Automation politique géographique"
            echo "  • Synchronisation temps avancée avec serveurs fallback"
            echo "  • Surveillance temps réel et détection dérive"
            echo "  • Journalisation audit complète et conformité"
            echo "  • Application politiques heures d'ouverture"
            echo "  • Intégration avec infrastructure MacFleet"
            ;;
    esac
}

# Exécuter la fonction principale avec tous les arguments
main "$@"

Commandes de Référence Rapide

Opérations Fuseaux Horaires de Base

# Vérifier le statut du fuseau horaire actuel
./timezone_manager.sh status

# Lister les fuseaux horaires disponibles
./timezone_manager.sh list-timezones

# Définir fuseau horaire avec politique entreprise
./timezone_manager.sh set America/New_York enterprise

# Valider fuseau horaire avant définition
./timezone_manager.sh validate Europe/London

Gestion Politique Géographique

# Appliquer les politiques géographiques prédéfinies
./timezone_manager.sh apply-policy US_EAST
./timezone_manager.sh apply-policy EU_LONDON
./timezone_manager.sh apply-policy ASIA_TOKYO

# Lister toutes les politiques géographiques disponibles
./timezone_manager.sh apply-policy

Synchronisation Heure

# Configurer synchronisation heure avec différentes politiques
./timezone_manager.sh sync enterprise    # Utiliser serveurs NTP entreprise
./timezone_manager.sh sync standard      # Utiliser serveur temps Apple
./timezone_manager.sh sync public        # Utiliser pool NTP public

# Surveiller santé synchronisation heure
./timezone_manager.sh monitor basic
./timezone_manager.sh monitor comprehensive

Heures d'Ouverture et Conformité

# Définir politiques heures d'ouverture
./timezone_manager.sh business-hours standard     # 09:00-17:00
./timezone_manager.sh business-hours extended     # 08:00-18:00
./timezone_manager.sh business-hours 24x7         # Opérations 24/7
./timezone_manager.sh business-hours custom "06:00-22:00"

# Générer rapports de conformité
./timezone_manager.sh report compliance
./timezone_manager.sh report audit

Exemples d'Intégration

Intégration JAMF Pro

#!/bin/bash

# Script JAMF Pro pour gestion fuseau horaire
# Paramètres : $4 = politique_géographique, $5 = politique_sync, $6 = heures_ouverture

POLITIQUE_GEOGRAPHIQUE="$4"
POLITIQUE_SYNC="$5"
HEURES_OUVERTURE="$6"

# Télécharger gestionnaire fuseau horaire s'il n'est pas présent
if [[ ! -f "/usr/local/bin/macfleet_timezone_manager.sh" ]]; then
    curl -o "/usr/local/bin/macfleet_timezone_manager.sh" \
         "https://scripts.macfleet.com/timezone_manager.sh"
    chmod +x "/usr/local/bin/macfleet_timezone_manager.sh"
fi

# Appliquer politique géographique
if [[ -n "$POLITIQUE_GEOGRAPHIQUE" ]]; then
    /usr/local/bin/macfleet_timezone_manager.sh apply-policy "$POLITIQUE_GEOGRAPHIQUE"
fi

# Configurer synchronisation heure
if [[ -n "$POLITIQUE_SYNC" ]]; then
    /usr/local/bin/macfleet_timezone_manager.sh sync "$POLITIQUE_SYNC"
fi

# Définir heures d'ouverture
if [[ -n "$HEURES_OUVERTURE" ]]; then
    /usr/local/bin/macfleet_timezone_manager.sh business-hours "$HEURES_OUVERTURE"
fi

# Rapporter statut à JAMF
echo "Configuration fuseau horaire terminée avec succès"

Meilleures Pratiques

  1. Utiliser serveurs NTP entreprise pour synchronisation temporelle cohérente
  2. Implémenter politiques géographiques pour organisations multi-sites
  3. Surveiller dérive temporelle en continu avec alertes automatisées
  4. Maintenir pistes d'audit pour exigences de conformité
  5. Tester connectivité serveur temps avant déploiement
  6. Utiliser serveurs temps de sauvegarde pour redondance
  7. Coordonner avec équipes réseau pour accès serveurs NTP
  8. Documenter politiques fuseaux horaires pour opérations métier

Ce système de gestion des fuseaux horaires entreprise fournit un contrôle complet du temps et de la date avec conformité géographique automatisée, application de politiques et capacités de surveillance de niveau entreprise pour une gestion temporelle MacFleet efficace.

Gestion d'Entreprise des Sauvegardes Time Machine sur macOS

Gérez et automatisez les sauvegardes Time Machine de votre MacFleet avec des politiques de sauvegarde de niveau entreprise et des capacités de récupération d'urgence. Ce tutoriel couvre la gestion avancée des sauvegardes, le déploiement à l'échelle de la flotte, la surveillance de conformité et les systèmes de récupération automatisés.

Comprendre la Gestion Time Machine d'Entreprise

La gestion des sauvegardes d'entreprise nécessite :

  • 🔄 Politiques de sauvegarde automatisées - Planifications de sauvegarde cohérentes sur tous les appareils
  • 🛡️ Planification de récupération d'urgence - Récupération rapide des incidents de perte de données
  • 📊 Surveillance de conformité - Pistes d'audit et conformité réglementaire
  • ⚡ Gestion de flotte - Contrôle et rapports de sauvegarde centralisés
  • 🔐 Sécurité et chiffrement - Données de sauvegarde protégées avec contrôles d'accès

Opérations de Base Time Machine

Définir la Destination de Sauvegarde

#!/bin/bash

# Définir la destination de sauvegarde Time Machine
BACKUP_DESTINATION="/Volumes/BackupDrive"

if [[ -d "$BACKUP_DESTINATION" ]]; then
    sudo tmutil setdestination "$BACKUP_DESTINATION"
    echo "✅ Destination de sauvegarde définie vers : $BACKUP_DESTINATION"
else
    echo "❌ Destination de sauvegarde non trouvée : $BACKUP_DESTINATION"
    exit 1
fi

Activer et Démarrer la Sauvegarde

#!/bin/bash

# Activer Time Machine et démarrer la sauvegarde
sudo tmutil enable
sudo tmutil startbackup

echo "✅ Time Machine activé et sauvegarde démarrée"

Vérifier le Statut de Sauvegarde

#!/bin/bash

# Vérifier le statut actuel de la sauvegarde
tmutil status

echo "📊 Statut actuel de sauvegarde affiché"

Lister les Sauvegardes Disponibles

#!/bin/bash

# Lister toutes les sauvegardes disponibles
tmutil listbackups

echo "📋 Sauvegardes disponibles listées"

Gestion Avancée des Sauvegardes

Configuration Intelligente de Destination de Sauvegarde

#!/bin/bash

# Destination de sauvegarde intelligente avec validation
setup_backup_destination() {
    local destination="$1"
    local min_space_gb="${2:-100}"  # Minimum 100GB par défaut
    
    echo "🔍 Validation de la destination de sauvegarde : $destination"
    
    # Vérifier si la destination existe
    if [[ ! -d "$destination" ]]; then
        echo "❌ Le répertoire de destination n'existe pas : $destination"
        return 1
    fi
    
    # Vérifier l'espace disponible
    local available_space=$(df -BG "$destination" | tail -1 | awk '{print $4}' | sed 's/G//')
    
    if [[ $available_space -lt $min_space_gb ]]; then
        echo "❌ Espace insuffisant : ${available_space}GB disponible, ${min_space_gb}GB requis"
        return 1
    fi
    
    # Vérifier les permissions d'écriture
    if [[ ! -w "$destination" ]]; then
        echo "❌ Pas de permission d'écriture vers la destination : $destination"
        return 1
    fi
    
    # Définir la destination
    sudo tmutil setdestination "$destination"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Destination de sauvegarde définie avec succès : $destination"
        echo "📊 Espace disponible : ${available_space}GB"
        return 0
    else
        echo "❌ Échec de la définition de la destination de sauvegarde"
        return 1
    fi
}

# Exemple d'utilisation
setup_backup_destination "/Volumes/Enterprise_Backup" 500

Gestion Avancée des Exclusions

#!/bin/bash

# Gestion des exclusions de sauvegarde d'entreprise
manage_backup_exclusions() {
    local action="$1"  # add, remove, list
    local path="$2"
    
    case "$action" in
        "add")
            if [[ -n "$path" ]]; then
                sudo tmutil addexclusion "$path"
                echo "✅ Exclusion ajoutée : $path"
                log_exclusion_change "added" "$path"
            else
                echo "❌ Chemin requis pour l'opération d'ajout"
                return 1
            fi
            ;;
        "remove")
            if [[ -n "$path" ]]; then
                sudo tmutil removeexclusion "$path"
                echo "✅ Exclusion supprimée : $path"
                log_exclusion_change "removed" "$path"
            else
                echo "❌ Chemin requis pour l'opération de suppression"
                return 1
            fi
            ;;
        "list")
            echo "📋 Exclusions actuelles :"
            tmutil listbackups | while read -r backup; do
                if [[ -d "$backup" ]]; then
                    echo "Vérification des exclusions pour : $backup"
                    # Lister les exclusions nécessiterait l'analyse des métadonnées de sauvegarde
                fi
            done
            ;;
        "enterprise_defaults")
            apply_enterprise_exclusions
            ;;
        *)
            echo "❌ Action invalide : $action"
            echo "Actions disponibles : add, remove, list, enterprise_defaults"
            return 1
            ;;
    esac
}

# Appliquer les exclusions d'entreprise standard
apply_enterprise_exclusions() {
    echo "🏢 Application des exclusions de sauvegarde d'entreprise..."
    
    local exclusions=(
        "/System/Library/Caches"
        "/Library/Caches"
        "~/Library/Caches"
        "/private/var/vm"
        "/cores"
        "/tmp"
        "/private/tmp"
        "~/.Trash"
        "/Applications/Xcode.app/Contents/Developer/Platforms"  # Gros fichiers de dev
        "/usr/local/var/log"  # Fichiers de log
        "~/Downloads"  # Téléchargements temporaires
    )
    
    for exclusion in "${exclusions[@]}"; do
        sudo tmutil addexclusion "$exclusion" 2>/dev/null
        echo "Exclusion ajoutée : $exclusion"
    done
    
    echo "✅ Exclusions d'entreprise appliquées"
}

# Journaliser les changements d'exclusion pour audit
log_exclusion_change() {
    local action="$1"
    local path="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local log_entry="[$timestamp] Exclusion $action : $path"
    
    echo "$log_entry" >> "/var/log/macfleet_backup_exclusions.log"
}

Surveillance de la Santé des Sauvegardes

#!/bin/bash

# Évaluation complète de la santé des sauvegardes
assess_backup_health() {
    echo "🏥 Évaluation de la santé des sauvegardes Time Machine..."
    
    local health_score=100
    local issues=()
    local warnings=()
    
    # Vérifier si Time Machine est activé
    local tm_enabled=$(tmutil status | grep "Running" | wc -l)
    if [[ $tm_enabled -eq 0 ]]; then
        health_score=$((health_score - 30))
        issues+=("Time Machine n'est pas en cours d'exécution")
    fi
    
    # Vérifier l'accessibilité des destinations de sauvegarde
    local destinations=$(tmutil destinationinfo | grep "URL" | wc -l)
    if [[ $destinations -eq 0 ]]; then
        health_score=$((health_score - 25))
        issues+=("Aucune destination de sauvegarde configurée")
    else
        # Vérifier si les destinations sont accessibles
        tmutil destinationinfo | grep "URL" | while read -r line; do
            local dest_path=$(echo "$line" | sed 's/.*URL : //')
            if [[ ! -d "$dest_path" ]]; then
                health_score=$((health_score - 15))
                issues+=("Destination de sauvegarde inaccessible : $dest_path")
            fi
        done
    fi
    
    # Vérifier l'heure de la dernière sauvegarde
    local last_backup=$(tmutil latestbackup 2>/dev/null)
    if [[ -n "$last_backup" ]]; then
        local last_backup_timestamp=$(stat -f %m "$last_backup" 2>/dev/null)
        local current_timestamp=$(date +%s)
        local hours_since_backup=$(( (current_timestamp - last_backup_timestamp) / 3600 ))
        
        if [[ $hours_since_backup -gt 48 ]]; then
            health_score=$((health_score - 20))
            issues+=("Dernière sauvegarde il y a $hours_since_backup heures")
        elif [[ $hours_since_backup -gt 24 ]]; then
            health_score=$((health_score - 10))
            warnings+=("Dernière sauvegarde il y a $hours_since_backup heures")
        fi
    else
        health_score=$((health_score - 25))
        issues+=("Aucune sauvegarde précédente trouvée")
    fi
    
    # Vérifier l'espace disque disponible sur la destination de sauvegarde
    local backup_dest=$(tmutil destinationinfo | grep "URL" | head -1 | sed 's/.*URL : //')
    if [[ -n "$backup_dest" ]] && [[ -d "$backup_dest" ]]; then
        local available_space=$(df -BG "$backup_dest" | tail -1 | awk '{print $4}' | sed 's/G//')
        if [[ $available_space -lt 10 ]]; then
            health_score=$((health_score - 15))
            issues+=("Espace disque faible sur la destination de sauvegarde : ${available_space}GB")
        elif [[ $available_space -lt 50 ]]; then
            warnings+=("L'espace de destination de sauvegarde devient faible : ${available_space}GB")
        fi
    fi
    
    # Générer le rapport de santé
    echo "📊 Score de Santé de Sauvegarde : $health_score/100"
    
    if [[ ${#issues[@]} -gt 0 ]]; then
        echo "🔴 Problèmes Critiques :"
        printf '   - %s\n' "${issues[@]}"
    fi
    
    if [[ ${#warnings[@]} -gt 0 ]]; then
        echo "⚠️ Avertissements :"
        printf '   - %s\n' "${warnings[@]}"
    fi
    
    if [[ $health_score -ge 90 ]]; then
        echo "✅ Le système de sauvegarde est en bonne santé"
    elif [[ $health_score -ge 70 ]]; then
        echo "⚠️ Le système de sauvegarde a des problèmes mineurs"
    else
        echo "🔴 Le système de sauvegarde nécessite une attention immédiate"
    fi
    
    return $health_score
}

Politiques de Sauvegarde d'Entreprise

Politique d'Environnement de Production

#!/bin/bash

# Politique de sauvegarde de production haute fréquence
apply_production_backup_policy() {
    echo "🏭 Application de la politique de sauvegarde de production..."
    
    # Activer Time Machine
    sudo tmutil enable
    
    # Définir un planning de sauvegarde agressif (toutes les 30 minutes)
    configure_backup_intervals 1800 900 600 60
    
    # Appliquer des exclusions minimales (conserver la plupart des données)
    local minimal_exclusions=(
        "/System/Library/Caches"
        "/private/var/vm"
        "/cores"
    )
    
    for exclusion in "${minimal_exclusions[@]}"; do
        sudo tmutil addexclusion "$exclusion" 2>/dev/null
    done
    
    # Activer la vérification de sauvegarde
    enable_backup_verification
    
    echo "✅ Politique de sauvegarde de production appliquée"
    log_policy_application "production"
}

Politique d'Environnement de Développement

#!/bin/bash

# Politique de sauvegarde optimisée pour le développement
apply_development_backup_policy() {
    echo "💻 Application de la politique de sauvegarde de développement..."
    
    # Activer Time Machine
    sudo tmutil enable
    
    # Définir un planning de sauvegarde modéré (toutes les 2 heures)
    configure_backup_intervals 7200 3600 1800 300
    
    # Exclure les artefacts de développement
    local dev_exclusions=(
        "/System/Library/Caches"
        "/Library/Caches"
        "~/Library/Caches"
        "/private/var/vm"
        "/cores"
        "~/Library/Developer/Xcode/DerivedData"
        "~/Library/Developer/CoreSimulator"
        "*/node_modules"
        "*/.git/objects"
        "*/target"
        "*/build"
        "*/.gradle"
        "*/.npm"
    )
    
    for exclusion in "${dev_exclusions[@]}"; do
        sudo tmutil addexclusion "$exclusion" 2>/dev/null
    done
    
    echo "✅ Politique de sauvegarde de développement appliquée"
    log_policy_application "development"
}

Politique Exécutive/Minimale

#!/bin/bash

# Politique de sauvegarde légère pour les cadres
apply_executive_backup_policy() {
    echo "🏢 Application de la politique de sauvegarde exécutive..."
    
    # Activer Time Machine
    sudo tmutil enable
    
    # Définir un planning de sauvegarde standard (toutes les 4 heures)
    configure_backup_intervals 14400 7200 3600 600
    
    # Exclure les fichiers non essentiels
    local executive_exclusions=(
        "/System/Library/Caches"
        "/Library/Caches"
        "~/Library/Caches"
        "/private/var/vm"
        "/cores"
        "~/Downloads"
        "~/Movies"
        "/Applications/Games"
        "~/Library/Application Support/Steam"
    )
    
    for exclusion in "${executive_exclusions[@]}"; do
        sudo tmutil addexclusion "$exclusion" 2>/dev/null
    done
    
    echo "✅ Politique de sauvegarde exécutive appliquée"
    log_policy_application "executive"
}