Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Aviso importante

Los ejemplos de código y scripts proporcionados en estos tutoriales son solo para propósitos educativos. Macfleet no es responsable de ningún problema, daño o vulnerabilidad de seguridad que pueda surgir del uso, modificación o implementación de estos ejemplos. Siempre revisa y prueba el código en un entorno seguro antes de usarlo en sistemas de producción.

Sharing User Management on macOS

Manage sharing-only user accounts across your MacFleet devices using advanced dscl commands. This tutorial covers user creation, security policies, bulk deployment, and enterprise user lifecycle management.

Understanding macOS User Management

macOS uses Directory Service command line utility (dscl) for user management:

  • dscl - Directory Service command line utility
  • Local Directory - /var/db/dslocal/nodes/Default
  • User Records - Stored in /Users/ path
  • Sharing-only Users - Limited access accounts for file sharing

Basic Sharing User Creation

Simple Sharing User

#!/bin/bash

# Create a basic sharing-only user account
USERNAME="SharingUser"
DISPLAY_NAME="Sharing Account"
PASSWORD="SecurePass123"
USER_ID="550"

# Create the user
sudo dscl . create /Users/"$USERNAME"

# Set display name
sudo dscl . create /Users/"$USERNAME" RealName "$DISPLAY_NAME"

# Set password
sudo dscl . passwd /Users/"$USERNAME" "$PASSWORD"

# Set unique ID
sudo dscl . create /Users/"$USERNAME" UniqueID "$USER_ID"

# Set group ID (staff group)
sudo dscl . create /Users/"$USERNAME" PrimaryGroupID 20

# Deny shell access
sudo dscl . create /Users/"$USERNAME" UserShell /usr/bin/false

# No home directory
sudo dscl . create /Users/"$USERNAME" NFSHomeDirectory /dev/null

echo "Sharing user '$USERNAME' created successfully"

Enhanced Sharing User with Options

#!/bin/bash

# Enhanced sharing user creation with additional options
create_sharing_user() {
    local username="$1"
    local display_name="$2"
    local password="$3"
    local hint="$4"
    local picture_path="$5"
    local user_id="$6"
    
    echo "Creating sharing user: $username"
    
    # Create user
    sudo dscl . create /Users/"$username"
    
    # Set display name
    sudo dscl . create /Users/"$username" RealName "$display_name"
    
    # Set password
    sudo dscl . passwd /Users/"$username" "$password"
    
    # Set password hint (optional)
    if [[ -n "$hint" ]]; then
        sudo dscl . create /Users/"$username" hint "$hint"
    fi
    
    # Set profile picture (optional)
    if [[ -n "$picture_path" && -f "$picture_path" ]]; then
        sudo dscl . create /Users/"$username" picture "$picture_path"
    fi
    
    # Set unique ID
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    
    # Set group ID
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    
    # Deny shell access
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    
    # No home directory
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    echo "✅ Sharing user '$username' created successfully"
    return 0
}

# Usage examples
create_sharing_user "FileShare" "File Sharing Account" "FilePass123" "File access only" "" "551"
create_sharing_user "GuestAccess" "Guest User" "GuestPass456" "Temporary access" "/System/Library/User Pictures/Animals/Butterfly.tif" "552"

Enterprise User Categories

User Type Classifications

#!/bin/bash

# Enterprise user categories with specific configurations
declare -A USER_CATEGORIES=(
    ["sharing_standard"]="Standard file sharing access"
    ["sharing_secure"]="High-security sharing with restrictions"
    ["guest_temporary"]="Temporary guest access with expiration"
    ["service_account"]="Service accounts for applications"
    ["departmental_shared"]="Department-specific shared accounts"
    ["external_partner"]="External partner limited access"
    ["kiosk_public"]="Public kiosk access accounts"
)

# Security policies for each category
declare -A SECURITY_POLICIES=(
    ["sharing_standard"]="password_policy:standard,audit_level:basic,session_timeout:8h"
    ["sharing_secure"]="password_policy:strong,audit_level:comprehensive,session_timeout:2h,mfa_required:true"
    ["guest_temporary"]="password_policy:basic,audit_level:full,session_timeout:1h,auto_expire:24h"
    ["service_account"]="password_policy:service,audit_level:system,no_interactive:true"
    ["departmental_shared"]="password_policy:department,audit_level:department,group_restrictions:true"
    ["external_partner"]="password_policy:external,audit_level:full,network_restrictions:true"
    ["kiosk_public"]="password_policy:public,audit_level:minimal,session_timeout:30m,reset_on_logout:true"
)

# Access control definitions
declare -A ACCESS_CONTROLS=(
    ["sharing_standard"]="file_sharing:read_write,print_access:yes,network_access:local"
    ["sharing_secure"]="file_sharing:read_only,print_access:restricted,network_access:vpn_only"
    ["guest_temporary"]="file_sharing:guest_folder,print_access:no,network_access:guest_wifi"
    ["service_account"]="file_sharing:service_dirs,print_access:no,network_access:service_ports"
    ["departmental_shared"]="file_sharing:department_dirs,print_access:department,network_access:department_vlan"
    ["external_partner"]="file_sharing:partner_dirs,print_access:no,network_access:partner_dmz"
    ["kiosk_public"]="file_sharing:public_docs,print_access:public,network_access:public_wifi"
)

print_user_categories() {
    echo "=== Available User Categories ==="
    for category in "${!USER_CATEGORIES[@]}"; do
        echo "Category: $category"
        echo "  Description: ${USER_CATEGORIES[$category]}"
        echo "  Security: ${SECURITY_POLICIES[$category]}"
        echo "  Access: ${ACCESS_CONTROLS[$category]}"
        echo ""
    done
}

# Display available categories
print_user_categories

User Management Policies

Password Policy Engine

#!/bin/bash

# Password policy definitions for different user types
generate_password_policy() {
    local policy_type="$1"
    
    case "$policy_type" in
        "standard")
            echo "min_length:8,complexity:medium,expiry:90d,history:5"
            ;;
        "strong")
            echo "min_length:12,complexity:high,expiry:60d,history:10,special_chars:required"
            ;;
        "basic")
            echo "min_length:6,complexity:low,expiry:never,history:3"
            ;;
        "service")
            echo "min_length:16,complexity:high,expiry:180d,history:20,machine_generated:true"
            ;;
        "department")
            echo "min_length:10,complexity:medium,expiry:120d,history:8,department_prefix:required"
            ;;
        "external")
            echo "min_length:14,complexity:high,expiry:30d,history:15,external_validation:required"
            ;;
        "public")
            echo "min_length:4,complexity:none,expiry:daily,history:1,auto_reset:true"
            ;;
        *)
            echo "min_length:8,complexity:medium,expiry:90d,history:5"
            ;;
    esac
}

# Generate secure password based on policy
generate_secure_password() {
    local policy="$1"
    local length
    local complexity
    
    # Parse policy
    length=$(echo "$policy" | grep -o 'min_length:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexity:[a-z]*' | cut -d: -f2)
    
    case "$complexity" in
        "high")
            # High complexity: uppercase, lowercase, numbers, special characters
            openssl rand -base64 $((length * 2)) | tr -d "=+/" | cut -c1-"$length" | sed 's/./&@1A/4'
            ;;
        "medium")
            # Medium complexity: uppercase, lowercase, numbers
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
        "low")
            # Low complexity: alphanumeric
            openssl rand -hex "$((length/2))" | cut -c1-"$length"
            ;;
        *)
            # Default medium complexity
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
    esac
}

# Validate password against policy
validate_password() {
    local password="$1"
    local policy="$2"
    local min_length complexity
    
    min_length=$(echo "$policy" | grep -o 'min_length:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexity:[a-z]*' | cut -d: -f2)
    
    # Check length
    if [[ ${#password} -lt $min_length ]]; then
        echo "❌ Password too short (minimum $min_length characters)"
        return 1
    fi
    
    # Check complexity
    case "$complexity" in
        "high")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] && "$password" =~ [^A-Za-z0-9] ]]; then
                echo "❌ Password must contain uppercase, lowercase, numbers, and special characters"
                return 1
            fi
            ;;
        "medium")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] ]]; then
                echo "❌ Password must contain uppercase, lowercase, and numbers"
                return 1
            fi
            ;;
    esac
    
    echo "✅ Password meets policy requirements"
    return 0
}

Enterprise User Deployment Profiles

Deployment Configuration Templates

#!/bin/bash

# Enterprise deployment profiles for different organizational needs
declare -A DEPLOYMENT_PROFILES=(
    ["corporate_standard"]="Standard corporate deployment with basic security"
    ["high_security_finance"]="High-security deployment for financial departments"
    ["guest_access_lobby"]="Guest access deployment for lobby/public areas"
    ["partner_collaboration"]="External partner collaboration deployment"
    ["kiosk_public_library"]="Public kiosk deployment for libraries/public spaces"
    ["research_development"]="Research and development team deployment"
    ["executive_secure"]="Executive-level secure deployment"
)

# Profile-specific configurations
get_deployment_config() {
    local profile="$1"
    
    case "$profile" in
        "corporate_standard")
            cat << EOF
{
    "user_category": "sharing_standard",
    "password_policy": "standard",
    "access_level": "department_files",
    "session_timeout": "8h",
    "audit_level": "basic",
    "group_membership": ["staff", "file_sharing"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false
    },
    "monitoring": {
        "login_tracking": true,
        "file_access_log": true,
        "failed_attempts": 5
    }
}
EOF
            ;;
        "high_security_finance")
            cat << EOF
{
    "user_category": "sharing_secure",
    "password_policy": "strong",
    "access_level": "finance_restricted",
    "session_timeout": "2h",
    "audit_level": "comprehensive",
    "group_membership": ["finance", "secure_sharing"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false,
        "network_access": "finance_vlan_only",
        "time_restrictions": "business_hours"
    },
    "security": {
        "mfa_required": true,
        "encryption": "aes256",
        "key_rotation": "monthly"
    },
    "monitoring": {
        "real_time_alerts": true,
        "login_tracking": true,
        "file_access_log": true,
        "failed_attempts": 3,
        "compliance_reporting": "sox_hipaa"
    }
}
EOF
            ;;
        "guest_access_lobby")
            cat << EOF
{
    "user_category": "guest_temporary",
    "password_policy": "basic",
    "access_level": "guest_resources",
    "session_timeout": "1h",
    "audit_level": "full",
    "group_membership": ["guest", "public_access"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false,
        "internet_access": "guest_wifi_only",
        "file_upload": false
    },
    "automation": {
        "auto_expire": "24h",
        "auto_cleanup": true,
        "reset_on_logout": true
    },
    "monitoring": {
        "session_recording": true,
        "login_tracking": true,
        "activity_log": true,
        "failed_attempts": 3
    }
}
EOF
            ;;
        *)
            echo "Unknown deployment profile: $profile"
            return 1
            ;;
    esac
}

# Apply deployment profile
apply_deployment_profile() {
    local profile="$1"
    local config_file="/tmp/deployment_config.json"
    
    echo "Applying deployment profile: $profile"
    
    # Get configuration
    get_deployment_config "$profile" > "$config_file"
    
    if [[ ! -f "$config_file" ]]; then
        echo "❌ Failed to generate configuration for profile: $profile"
        return 1
    fi
    
    echo "✅ Deployment configuration ready"
    echo "Configuration saved to: $config_file"
    
    # Parse and display key settings
    echo "=== Profile Summary ==="
    echo "User Category: $(jq -r '.user_category' "$config_file")"
    echo "Password Policy: $(jq -r '.password_policy' "$config_file")"
    echo "Access Level: $(jq -r '.access_level' "$config_file")"
    echo "Session Timeout: $(jq -r '.session_timeout' "$config_file")"
    echo "Audit Level: $(jq -r '.audit_level' "$config_file")"
    
    return 0
}

Enterprise User Management System

#!/bin/bash

# MacFleet Enterprise User Management System
# Comprehensive sharing user creation and management

# Configuration
CONFIG_DIR="/etc/macfleet/users"
LOG_FILE="/var/log/macfleet_user_management.log"
BACKUP_DIR="/var/backups/macfleet/users"
REPORTS_DIR="/var/reports/macfleet/users"
AUDIT_LOG="/var/log/macfleet_user_audit.log"

# Create required directories
create_directories() {
    local directories=("$CONFIG_DIR" "$BACKUP_DIR" "$REPORTS_DIR")
    
    for dir in "${directories[@]}"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            sudo chmod 755 "$dir"
        fi
    done
}

# Logging functions
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" | tee -a "$LOG_FILE" >&2
}

audit_log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [AUDIT] $1" | tee -a "$AUDIT_LOG"
}

# User ID management
get_next_user_id() {
    local start_id="$1"
    local current_id="$start_id"
    
    while dscl . list /Users UniqueID | awk '{print $2}' | grep -q "^${current_id}$"; do
        ((current_id++))
    done
    
    echo "$current_id"
}

# Comprehensive user creation function
create_enterprise_user() {
    local username="$1"
    local display_name="$2"
    local user_category="$3"
    local deployment_profile="$4"
    local department="$5"
    local expiry_date="$6"
    
    log_action "Starting user creation: $username (Category: $user_category, Profile: $deployment_profile)"
    
    # Validate inputs
    if [[ -z "$username" || -z "$display_name" || -z "$user_category" ]]; then
        log_error "Missing required parameters for user creation"
        return 1
    fi
    
    # Check if user already exists
    if dscl . read /Users/"$username" &>/dev/null; then
        log_error "User $username already exists"
        return 1
    fi
    
    # Get deployment configuration
    local config_file="/tmp/user_config_${username}.json"
    get_deployment_config "$deployment_profile" > "$config_file"
    
    # Parse configuration
    local password_policy
    password_policy=$(jq -r '.password_policy' "$config_file")
    
    # Get next available user ID
    local user_id
    user_id=$(get_next_user_id 550)
    
    # Generate secure password
    local policy_details
    policy_details=$(generate_password_policy "$password_policy")
    local password
    password=$(generate_secure_password "$policy_details")
    
    # Create user metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    cat > "$metadata_file" << EOF
{
    "username": "$username",
    "display_name": "$display_name",
    "user_category": "$user_category",
    "deployment_profile": "$deployment_profile",
    "department": "$department",
    "user_id": $user_id,
    "created_date": "$(date -Iseconds)",
    "created_by": "$(whoami)",
    "expiry_date": "$expiry_date",
    "password_policy": "$password_policy",
    "status": "active"
}
EOF
    
    # Create the user
    log_action "Creating user record for $username"
    sudo dscl . create /Users/"$username" || {
        log_error "Failed to create user record for $username"
        return 1
    }
    
    # Set basic properties
    sudo dscl . create /Users/"$username" RealName "$display_name"
    sudo dscl . passwd /Users/"$username" "$password"
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    # Add custom attributes
    sudo dscl . create /Users/"$username" Comment "MacFleet managed user - $user_category"
    sudo dscl . create /Users/"$username" Keywords "macfleet,$user_category,$deployment_profile,$department"
    
    # Set expiry date if provided
    if [[ -n "$expiry_date" ]]; then
        sudo dscl . create /Users/"$username" ExpiryDate "$expiry_date"
    fi
    
    # Apply group memberships
    local groups
    groups=$(jq -r '.group_membership[]' "$config_file" 2>/dev/null)
    while IFS= read -r group; do
        if [[ -n "$group" && "$group" != "null" ]]; then
            sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null || {
                log_action "Group $group does not exist, skipping"
            }
        fi
    done <<< "$groups"
    
    # Store secure password (encrypted)
    echo "$password" | openssl enc -aes-256-cbc -pbkdf2 -k "macfleet_$(hostname)" -out "$CONFIG_DIR/${username}_password.enc"
    
    # Create backup
    create_user_backup "$username"
    
    # Audit logging
    audit_log "User created: $username (UID: $user_id, Category: $user_category, Profile: $deployment_profile)"
    
    log_action "✅ User $username created successfully (UID: $user_id)"
    
    # Return password for initial communication (in production, use secure delivery)
    echo "CREATED_USER_INFO:$username:$password:$user_id"
    
    return 0
}

# Bulk user creation
bulk_create_users() {
    local csv_file="$1"
    local created_count=0
    local failed_count=0
    
    if [[ ! -f "$csv_file" ]]; then
        log_error "CSV file not found: $csv_file"
        return 1
    fi
    
    log_action "Starting bulk user creation from: $csv_file"
    
    # Process CSV file (skip header)
    tail -n +2 "$csv_file" | while IFS=',' read -r username display_name category profile department expiry; do
        if create_enterprise_user "$username" "$display_name" "$category" "$profile" "$department" "$expiry"; then
            ((created_count++))
        else
            ((failed_count++))
        fi
    done
    
    log_action "Bulk creation completed. Created: $created_count, Failed: $failed_count"
    
    # Generate report
    generate_user_report "bulk_creation_$(date +%Y%m%d_%H%M%S)"
}

# User management functions
list_enterprise_users() {
    echo "=== MacFleet Managed Users ==="
    echo "Username | Display Name | Category | Status | Created"
    echo "---------|--------------|----------|--------|--------"
    
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local username display_name category status created_date
            username=$(jq -r '.username' "$metadata_file")
            display_name=$(jq -r '.display_name' "$metadata_file")
            category=$(jq -r '.user_category' "$metadata_file")
            status=$(jq -r '.status' "$metadata_file")
            created_date=$(jq -r '.created_date' "$metadata_file" | cut -d'T' -f1)
            
            printf "%-8s | %-12s | %-8s | %-6s | %s\n" "$username" "$display_name" "$category" "$status" "$created_date"
        fi
    done
}

# User removal with cleanup
remove_enterprise_user() {
    local username="$1"
    local backup_before_removal="$2"
    
    log_action "Starting removal of user: $username"
    
    # Check if user exists
    if ! dscl . read /Users/"$username" &>/dev/null; then
        log_error "User $username does not exist"
        return 1
    fi
    
    # Create backup before removal
    if [[ "$backup_before_removal" == "true" ]]; then
        create_user_backup "$username"
    fi
    
    # Remove user from system
    sudo dscl . delete /Users/"$username" || {
        log_error "Failed to remove user $username from system"
        return 1
    }
    
    # Update metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        jq '.status = "deleted" | .deleted_date = now | .deleted_by = "'"$(whoami)"'"' "$metadata_file" > "${metadata_file}.tmp" && mv "${metadata_file}.tmp" "$metadata_file"
    fi
    
    # Audit logging
    audit_log "User removed: $username by $(whoami)"
    
    log_action "✅ User $username removed successfully"
    return 0
}

# User backup and restore
create_user_backup() {
    local username="$1"
    local backup_file="$BACKUP_DIR/${username}_backup_$(date +%Y%m%d_%H%M%S).plist"
    
    log_action "Creating backup for user: $username"
    
    # Export user record
    sudo dscl . read /Users/"$username" > "$backup_file"
    
    # Backup metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        cp "$metadata_file" "$BACKUP_DIR/${username}_metadata_$(date +%Y%m%d_%H%M%S).json"
    fi
    
    log_action "✅ User backup created: $backup_file"
}

# System health monitoring
monitor_user_system() {
    echo "=== User System Health Check ==="
    
    # Check for expired users
    local expired_users=0
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local expiry_date username
            expiry_date=$(jq -r '.expiry_date' "$metadata_file")
            username=$(jq -r '.username' "$metadata_file")
            
            if [[ "$expiry_date" != "null" && "$expiry_date" != "" ]]; then
                if [[ $(date -d "$expiry_date" +%s 2>/dev/null) -lt $(date +%s) ]]; then
                    echo "⚠️  Expired user: $username (expired: $expiry_date)"
                    ((expired_users++))
                fi
            fi
        fi
    done
    
    # Check for orphaned user records
    local system_users
    system_users=$(dscl . list /Users | grep -E "^(Sharing|Guest|Service|External)" || true)
    local orphaned_users=0
    
    while IFS= read -r user; do
        if [[ -n "$user" && ! -f "$CONFIG_DIR/${user}_metadata.json" ]]; then
            echo "⚠️  Orphaned user (no metadata): $user"
            ((orphaned_users++))
        fi
    done <<< "$system_users"
    
    # Summary
    echo ""
    echo "Health Summary:"
    echo "  Expired users: $expired_users"
    echo "  Orphaned users: $orphaned_users"
    
    if [[ $expired_users -eq 0 && $orphaned_users -eq 0 ]]; then
        echo "✅ User system is healthy"
    else
        echo "⚠️  User system requires attention"
    fi
}

# Generate comprehensive reports
generate_user_report() {
    local report_name="$1"
    local report_file="$REPORTS_DIR/${report_name}.json"
    
    log_action "Generating user report: $report_name"
    
    # Collect user statistics
    local total_users active_users inactive_users
    total_users=$(find "$CONFIG_DIR" -name "*_metadata.json" | wc -l)
    active_users=$(grep -l '"status": "active"' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | wc -l)
    inactive_users=$((total_users - active_users))
    
    # Category breakdown
    local categories
    categories=$(jq -r '.user_category' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | sort | uniq -c | awk '{print "{\"category\": \"" $2 "\", \"count\": " $1 "}"}' | jq -s '.')
    
    # Generate report
    cat > "$report_file" << EOF
{
    "report_name": "$report_name",
    "generated_date": "$(date -Iseconds)",
    "generated_by": "$(whoami)",
    "hostname": "$(hostname)",
    "statistics": {
        "total_users": $total_users,
        "active_users": $active_users,
        "inactive_users": $inactive_users
    },
    "category_breakdown": $categories,
    "system_info": {
        "macfleet_version": "2025.07.07",
        "os_version": "$(sw_vers -productVersion)",
        "hostname": "$(hostname)"
    }
}
EOF
    
    log_action "✅ Report generated: $report_file"
    echo "Report saved to: $report_file"
}

# Fleet deployment functions
deploy_to_fleet() {
    local fleet_config="$1"
    local user_config="$2"
    
    log_action "Starting fleet deployment"
    
    if [[ ! -f "$fleet_config" ]]; then
        log_error "Fleet configuration file not found: $fleet_config"
        return 1
    fi
    
    if [[ ! -f "$user_config" ]]; then
        log_error "User configuration file not found: $user_config"
        return 1
    fi
    
    # Read fleet configuration
    local hosts
    hosts=$(jq -r '.hosts[]' "$fleet_config")
    
    # Deploy to each host
    while IFS= read -r host; do
        if [[ -n "$host" ]]; then
            log_action "Deploying to host: $host"
            
            # Copy user management script and configuration
            scp "$0" "$user_config" "root@${host}:/tmp/" || {
                log_error "Failed to copy files to $host"
                continue
            }
            
            # Execute deployment on remote host
            ssh "root@${host}" "chmod +x /tmp/$(basename "$0") && /tmp/$(basename "$0") deploy_from_config /tmp/$(basename "$user_config")" || {
                log_error "Failed to execute deployment on $host"
                continue
            }
            
            log_action "✅ Deployment completed on: $host"
        fi
    done <<< "$hosts"
    
    log_action "Fleet deployment completed"
}

# Main function with command routing
main() {
    local command="$1"
    shift
    
    # Initialize
    create_directories
    
    case "$command" in
        "create")
            create_enterprise_user "$@"
            ;;
        "bulk_create")
            bulk_create_users "$@"
            ;;
        "list")
            list_enterprise_users
            ;;
        "remove")
            remove_enterprise_user "$@"
            ;;
        "backup")
            create_user_backup "$@"
            ;;
        "monitor")
            monitor_user_system
            ;;
        "report")
            generate_user_report "$@"
            ;;
        "deploy_fleet")
            deploy_to_fleet "$@"
            ;;
        "show_categories")
            print_user_categories
            ;;
        "show_policies")
            for policy in standard strong basic service department external public; do
                echo "Policy: $policy"
                echo "  $(generate_password_policy "$policy")"
                echo ""
            done
            ;;
        *)
            echo "MacFleet Enterprise User Management System"
            echo "Usage: $0 <command> [options]"
            echo ""
            echo "Commands:"
            echo "  create <username> <display_name> <category> <profile> [department] [expiry]"
            echo "  bulk_create <csv_file>"
            echo "  list"
            echo "  remove <username> [backup_before_removal]"
            echo "  backup <username>"
            echo "  monitor"
            echo "  report <report_name>"
            echo "  deploy_fleet <fleet_config> <user_config>"
            echo "  show_categories"
            echo "  show_policies"
            echo ""
            echo "Examples:"
            echo "  $0 create FileShare 'File Sharing Account' sharing_standard corporate_standard IT"
            echo "  $0 bulk_create users.csv"
            echo "  $0 list"
            echo "  $0 monitor"
            echo "  $0 report monthly_audit"
            ;;
    esac
}

# Execute main function with all arguments
main "$@"

Fleet Deployment Example

CSV Template for Bulk Creation

username,display_name,category,profile,department,expiry
FileShare01,File Sharing Account 1,sharing_standard,corporate_standard,IT,
GuestLobby,Guest Lobby Access,guest_temporary,guest_access_lobby,Reception,2025-12-31
PartnerExt,External Partner Access,sharing_secure,partner_collaboration,Legal,2025-09-30
KioskLib,Library Kiosk Account,kiosk_public,kiosk_public_library,Public,
FinanceShare,Finance Shared Account,sharing_secure,high_security_finance,Finance,
DevTeam,Development Team Share,sharing_standard,research_development,Engineering,

Fleet Configuration Example

{
    "fleet_name": "MacFleet Corporate",
    "deployment_date": "2025-07-07",
    "hosts": [
        "mac-office-01.company.com",
        "mac-office-02.company.com",
        "mac-conference-01.company.com"
    ],
    "deployment_profile": "corporate_standard",
    "security_policy": "enterprise_standard",
    "monitoring": {
        "enabled": true,
        "reporting_interval": "daily",
        "alert_threshold": "high"
    }
}

Security Considerations

User Account Security

  • No Shell Access - Sharing users cannot access command line
  • No Home Directory - Prevents file storage in user directories
  • Limited Group Membership - Restricts system access
  • Password Policies - Enforces strong password requirements
  • Audit Logging - Tracks all user management activities

Enterprise Compliance

  • SOX Compliance - Financial user access controls
  • HIPAA Compliance - Healthcare data protection
  • NIST Framework - Security control implementation
  • ISO 27001 - Information security management

Troubleshooting Guide

Common Issues

User Creation Fails

  • Check if user ID is already in use
  • Verify administrative privileges
  • Ensure directory services are running

Authentication Problems

  • Verify password policy compliance
  • Check user account status
  • Review audit logs for failed attempts

Permission Errors

  • Confirm group memberships
  • Check file sharing permissions
  • Verify security policy application

Diagnostic Commands

# Check user existence
dscl . read /Users/username

# List all users
dscl . list /Users

# Check user groups
groups username

# View user properties
id username

Important Notes

  • Test thoroughly before fleet deployment
  • Backup user data before making changes
  • Monitor audit logs for security events
  • Update policies based on security requirements
  • Document changes for compliance auditing
  • Use secure password delivery methods in production

Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Configurando un Runner de GitHub Actions en un Mac Mini (Apple Silicon)

Runner de GitHub Actions

GitHub Actions es una plataforma poderosa de CI/CD que te permite automatizar tus flujos de trabajo de desarrollo de software. Aunque GitHub ofrece runners hospedados, los runners auto-hospedados proporcionan mayor control y personalización para tu configuración de CI/CD. Este tutorial te guía a través de la configuración y conexión de un runner auto-hospedado en un Mac mini para ejecutar pipelines de macOS.

Prerrequisitos

Antes de comenzar, asegúrate de tener:

  • Un Mac mini (regístrate en Macfleet)
  • Un repositorio de GitHub con derechos de administrador
  • Un gestor de paquetes instalado (preferiblemente Homebrew)
  • Git instalado en tu sistema

Paso 1: Crear una Cuenta de Usuario Dedicada

Primero, crea una cuenta de usuario dedicada para el runner de GitHub Actions:

# Crear la cuenta de usuario 'gh-runner'
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Establecer la contraseña para el usuario
sudo dscl . -passwd /Users/gh-runner tu_contraseña

# Agregar 'gh-runner' al grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Cambia a la nueva cuenta de usuario:

su gh-runner

Paso 2: Instalar Software Requerido

Instala Git y Rosetta 2 (si usas Apple Silicon):

# Instalar Git si no está ya instalado
brew install git

# Instalar Rosetta 2 para Macs Apple Silicon
softwareupdate --install-rosetta

Paso 3: Configurar el Runner de GitHub Actions

  1. Ve a tu repositorio de GitHub
  2. Navega a Configuración > Actions > Runners

Runner de GitHub Actions

  1. Haz clic en "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecciona macOS como imagen del runner y ARM64 como arquitectura
  3. Sigue los comandos proporcionados para descargar y configurar el runner

Runner de GitHub Actions

Crea un archivo .env en el directorio _work del runner:

# archivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Ejecuta el script run.sh en tu directorio del runner para completar la configuración.
  2. Verifica que el runner esté activo y escuchando trabajos en la terminal y revisa la configuración del repositorio de GitHub para la asociación del runner y el estado Idle.

Runner de GitHub Actions

Paso 4: Configurar Sudoers (Opcional)

Si tus acciones requieren privilegios de root, configura el archivo sudoers:

sudo visudo

Agrega la siguiente línea:

gh-runner ALL=(ALL) NOPASSWD: ALL

Paso 5: Usar el Runner en Flujos de Trabajo

Configura tu flujo de trabajo de GitHub Actions para usar el runner auto-hospedado:

name: Flujo de trabajo de muestra

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - name: Instalar NodeJS
        run: brew install node

El runner está autenticado en tu repositorio y etiquetado con self-hosted, macOS, y ARM64. Úsalo en tus flujos de trabajo especificando estas etiquetas en el campo runs-on:

runs-on: [self-hosted, macOS, ARM64]

Mejores Prácticas

  • Mantén tu software del runner actualizado
  • Monitorea regularmente los logs del runner para problemas
  • Usa etiquetas específicas para diferentes tipos de runners
  • Implementa medidas de seguridad apropiadas
  • Considera usar múltiples runners para balanceo de carga

Solución de Problemas

Problemas comunes y soluciones:

  1. Runner no conectando:

    • Verifica conectividad de red
    • Verifica validez del token de GitHub
    • Asegúrate de permisos apropiados
  2. Fallas de construcción:

    • Verifica instalación de Xcode
    • Verifica dependencias requeridas
    • Revisa logs del flujo de trabajo
  3. Problemas de permisos:

    • Verifica permisos de usuario
    • Verifica configuración de sudoers
    • Revisa permisos del sistema de archivos

Conclusión

Ahora tienes un runner auto-hospedado de GitHub Actions configurado en tu Mac mini. Esta configuración te proporciona más control sobre tu entorno de CI/CD y te permite ejecutar flujos de trabajo específicos de macOS de manera eficiente.

Recuerda mantener regularmente tu runner y mantenerlo actualizado con los últimos parches de seguridad y versiones de software.

Aplicación Nativa

Aplicación nativa de Macfleet

Guía de Instalación de Macfleet

Macfleet es una solución poderosa de gestión de flota diseñada específicamente para entornos de Mac Mini alojados en la nube. Como proveedor de hosting en la nube de Mac Mini, puedes usar Macfleet para monitorear, gestionar y optimizar toda tu flota de instancias Mac virtualizadas.

Esta guía de instalación te llevará a través de la configuración del monitoreo de Macfleet en sistemas macOS, Windows y Linux para asegurar una supervisión integral de tu infraestructura en la nube.

🍎 macOS

  • Descarga el archivo .dmg para Mac aquí
  • Haz doble clic en el archivo .dmg descargado
  • Arrastra la aplicación Macfleet a la carpeta Aplicaciones
  • Expulsa el archivo .dmg
  • Abre Preferencias del Sistema > Seguridad y Privacidad
    • Pestaña Privacidad > Accesibilidad
    • Marca Macfleet para permitir el monitoreo
  • Inicia Macfleet desde Aplicaciones
  • El seguimiento comienza automáticamente

🪟 Windows

  • Descarga el archivo .exe para Windows aquí
  • Haz clic derecho en el archivo .exe > "Ejecutar como administrador"
  • Sigue el asistente de instalación
  • Acepta los términos y condiciones
  • Permite en Windows Defender si se solicita
  • Concede permisos de monitoreo de aplicaciones
  • Inicia Macfleet desde el Menú Inicio
  • La aplicación comienza el seguimiento automáticamente

🐧 Linux

  • Descarga el paquete .deb (Ubuntu/Debian) o .rpm (CentOS/RHEL) aquí
  • Instala usando tu gestor de paquetes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permite permisos de acceso X11 si se solicita
  • Agrega el usuario a los grupos apropiados si es necesario
  • Inicia Macfleet desde el menú de Aplicaciones
  • La aplicación comienza el seguimiento automáticamente

Nota: Después de la instalación en todos los sistemas, inicia sesión con tus credenciales de Macfleet para sincronizar datos con tu panel de control.