Restricción de Permisos

Implementación de sistemas robustos de control de acceso y seguridad de archivos

Módulo 10 ⏱️ 40-45 min 🔐 Permisos 🛡️ ACL 📊 Avanzado

Fundamentos de Control de Acceso

La gestión adecuada de permisos es una de las piedras angulares de la seguridad en sistemas Linux. Un sistema mal configurado puede permitir accesos no autorizados, escalación de privilegios, o comprometer datos sensibles. Como administradores de sistemas, debemos implementar políticas de permisos restrictivas que sigan el principio de menor privilegio.

En esta lección exploraremos técnicas avanzadas para implementar controles de acceso robustos, desde permisos tradicionales Unix hasta ACLs (Access Control Lists) y mecanismos de seguridad adicionales como umask, sticky bits, y herramientas de auditoría.

Principios de Seguridad en Permisos
  • Principio de menor privilegio: Otorgar solo los permisos mínimos necesarios
  • Separación de responsabilidades: Dividir privilegios entre roles específicos
  • Defensa en profundidad: Múltiples capas de control de acceso
  • Auditoría continua: Monitoreo constante de accesos y cambios
Riesgos Comunes
  • Permisos 777 en archivos críticos del sistema
  • Directorios /tmp sin sticky bit activado
  • Scripts con permisos de escritura para grupo/otros
  • Archivos de configuración legibles por usuarios no privilegiados

Gestión Avanzada de Permisos Básicos

Script de Auditoría de Permisos

Herramienta completa para auditar y corregir permisos inseguros en el sistema.

permission_auditor.sh Copiar
#!/bin/bash

# Sistema de Auditoría y Corrección de Permisos
# Identifica y corrige configuraciones inseguras de permisos

# ========================================
# CONFIGURACIÓN GLOBAL
# ========================================

readonly SCRIPT_NAME="$(basename "$0")"
readonly LOG_FILE="/var/log/permission_audit.log"
readonly REPORT_FILE="/tmp/permission_audit_$(date +%Y%m%d_%H%M%S).txt"
readonly FIX_SCRIPT="/tmp/permission_fixes_$(date +%Y%m%d_%H%M%S).sh"

# Configuración de auditoría
readonly AUDIT_PATHS=(
    "/etc"
    "/var/www"
    "/home"
    "/opt"
    "/usr/local"
    "/tmp"
    "/var/tmp"
)

# Patrones de archivos críticos
readonly CRITICAL_FILES=(
    "/etc/passwd"
    "/etc/shadow"
    "/etc/sudoers"
    "/etc/ssh/sshd_config"
    "/etc/crontab"
    "/etc/fstab"
)

# Configuración de permisos seguros
readonly SECURE_PERMS=(
    "/etc/passwd:644:root:root"
    "/etc/shadow:640:root:shadow"
    "/etc/sudoers:440:root:root"
    "/etc/ssh/sshd_config:600:root:root"
    "/tmp:1777:root:root"
    "/var/tmp:1777:root:root"
)

# Colores para output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'

# ========================================
# FUNCIONES DE UTILIDAD
# ========================================

log_message() {
    local level="$1"
    local message="$2"
    local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
    
    echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
    
    case "$level" in
        ERROR)   echo -e "${RED}[ERROR]${NC} $message" >&2 ;;
        WARNING) echo -e "${YELLOW}[WARNING]${NC} $message" >&2 ;;
        INFO)    echo -e "${BLUE}[INFO]${NC} $message" ;;
        SUCCESS) echo -e "${GREEN}[SUCCESS]${NC} $message" ;;
    esac
}

# Verificar si se ejecuta como root
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_message "ERROR" "Este script debe ejecutarse como root para auditoría completa"
        exit 1
    fi
}

# ========================================
# FUNCIONES DE AUDITORÍA
# ========================================

# Buscar archivos con permisos peligrosos
audit_dangerous_permissions() {
    log_message "INFO" "Auditando permisos peligrosos..."
    
    local findings=0
    
    echo "=== ARCHIVOS CON PERMISOS PELIGROSOS ===" >> "$REPORT_FILE"
    
    # Buscar archivos 777 (mundo escribible)
    echo "Archivos con permisos 777:" >> "$REPORT_FILE"
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            find "$path" -type f -perm 0777 2>/dev/null | while read -r file; do
                echo "  CRÍTICO: $file (777 - mundo escribible)" | tee -a "$REPORT_FILE"
                ((findings++))
            done
        fi
    done
    
    # Buscar archivos con bit SUID peligrosos
    echo -e "\nArchivos con bit SUID:" >> "$REPORT_FILE"
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            find "$path" -type f -perm /4000 2>/dev/null | while read -r file; do
                local owner=$(stat -c %U "$file")
                if [[ "$owner" == "root" ]]; then
                    echo "  ADVERTENCIA: $file (SUID root)" | tee -a "$REPORT_FILE"
                else
                    echo "  INFO: $file (SUID $owner)" | tee -a "$REPORT_FILE"
                fi
                ((findings++))
            done
        fi
    done
    
    # Buscar directorios mundo escribibles sin sticky bit
    echo -e "\nDirectorios mundo escribibles sin sticky bit:" >> "$REPORT_FILE"
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            find "$path" -type d -perm -0002 ! -perm -1000 2>/dev/null | while read -r dir; do
                echo "  CRÍTICO: $dir (mundo escribible sin sticky bit)" | tee -a "$REPORT_FILE"
                ((findings++))
            done
        fi
    done
    
    log_message "INFO" "Auditoría de permisos peligrosos completada. Findings: $findings"
}

# Auditar archivos críticos del sistema
audit_critical_files() {
    log_message "INFO" "Auditando archivos críticos del sistema..."
    
    echo -e "\n=== AUDITORÍA DE ARCHIVOS CRÍTICOS ===" >> "$REPORT_FILE"
    
    for file in "${CRITICAL_FILES[@]}"; do
        if [[ -e "$file" ]]; then
            local perms=$(stat -c %a "$file")
            local owner=$(stat -c %U "$file")
            local group=$(stat -c %G "$file")
            
            echo "Archivo: $file" >> "$REPORT_FILE"
            echo "  Permisos: $perms" >> "$REPORT_FILE"
            echo "  Propietario: $owner:$group" >> "$REPORT_FILE"
            
            # Verificar configuraciones específicas
            case "$file" in
                "/etc/shadow")
                    if [[ "$perms" != "640" ]] || [[ "$owner" != "root" ]]; then
                        echo "  CRÍTICO: Permisos inseguros en $file" | tee -a "$REPORT_FILE"
                    fi
                    ;;
                "/etc/sudoers")
                    if [[ "$perms" != "440" ]] || [[ "$owner" != "root" ]]; then
                        echo "  CRÍTICO: Permisos inseguros en $file" | tee -a "$REPORT_FILE"
                    fi
                    ;;
                "/etc/ssh/sshd_config")
                    if [[ "$perms" != "600" ]] || [[ "$owner" != "root" ]]; then
                        echo "  ADVERTENCIA: Permisos subóptimos en $file" | tee -a "$REPORT_FILE"
                    fi
                    ;;
            esac
            
            echo "" >> "$REPORT_FILE"
        else
            echo "ADVERTENCIA: Archivo crítico no encontrado: $file" | tee -a "$REPORT_FILE"
        fi
    done
}

# Buscar archivos de configuración legibles por todos
audit_config_files() {
    log_message "INFO" "Auditando archivos de configuración..."
    
    echo -e "\n=== ARCHIVOS DE CONFIGURACIÓN EXPUESTOS ===" >> "$REPORT_FILE"
    
    # Patrones de archivos de configuración
    local config_patterns=(
        "*.conf"
        "*.cfg" 
        "*.config"
        "*.ini"
        "*.properties"
        ".env"
        "*password*"
        "*secret*"
        "*key*"
    )
    
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            for pattern in "${config_patterns[@]}"; do
                find "$path" -name "$pattern" -type f -perm /044 2>/dev/null | while read -r file; do
                    # Verificar si contiene información sensible
                    if grep -q -i "password\|secret\|key\|token" "$file" 2>/dev/null; then
                        echo "  CRÍTICO: $file (contiene credenciales y es legible)" | tee -a "$REPORT_FILE"
                    else
                        echo "  INFO: $file (archivo de configuración legible)" >> "$REPORT_FILE"
                    fi
                done
            done
        fi
    done
}

# Auditar scripts ejecutables
audit_scripts() {
    log_message "INFO" "Auditando scripts ejecutables..."
    
    echo -e "\n=== SCRIPTS EJECUTABLES ===" >> "$REPORT_FILE"
    
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            # Buscar scripts con permisos de escritura para grupo/otros
            find "$path" -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.py" -o -name "*.pl" \) -executable -perm /022 2>/dev/null | while read -r script; do
                local perms=$(stat -c %a "$script")
                local owner=$(stat -c %U "$script")
                echo "  ADVERTENCIA: $script (permisos $perms, propietario $owner) - escribible por grupo/otros" | tee -a "$REPORT_FILE"
            done
            
            # Buscar scripts SUID/SGID
            find "$path" -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.py" -o -name "*.pl" \) -executable -perm /6000 2>/dev/null | while read -r script; do
                local perms=$(stat -c %a "$script")
                echo "  CRÍTICO: $script (permisos $perms) - script con SUID/SGID" | tee -a "$REPORT_FILE"
            done
        fi
    done
}

# ========================================
# FUNCIONES DE CORRECCIÓN
# ========================================

# Generar script de corrección automática
generate_fix_script() {
    log_message "INFO" "Generando script de corrección..."
    
    cat > "$FIX_SCRIPT" << 'EOF'
#!/bin/bash
# Script de corrección automática de permisos
# Generado por permission_auditor.sh

set -euo pipefail

echo "Aplicando correcciones de permisos de seguridad..."

# Función de logging
log_fix() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
EOF
    
    # Agregar correcciones para archivos críticos
    echo -e "\n# Corregir permisos de archivos críticos" >> "$FIX_SCRIPT"
    for perm_config in "${SECURE_PERMS[@]}"; do
        IFS=':' read -r file perms owner group <<< "$perm_config"
        if [[ -e "$file" ]]; then
            cat >> "$FIX_SCRIPT" << EOF
if [[ -e "$file" ]]; then
    log_fix "Corrigiendo permisos de $file"
    chmod $perms "$file"
    chown $owner:$group "$file"
fi

EOF
        fi
    done
    
    # Buscar y corregir archivos 777
    echo "# Corregir archivos con permisos 777" >> "$FIX_SCRIPT"
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            find "$path" -type f -perm 0777 2>/dev/null | while read -r file; do
                echo "log_fix \"Corrigiendo permisos 777 en $file\"" >> "$FIX_SCRIPT"
                echo "chmod 755 \"$file\"" >> "$FIX_SCRIPT"
            done
        fi
    done
    
    # Corregir directorios mundo escribibles sin sticky bit
    echo -e "\n# Corregir directorios mundo escribibles" >> "$FIX_SCRIPT"
    for path in "${AUDIT_PATHS[@]}"; do
        if [[ -d "$path" ]]; then
            find "$path" -type d -perm -0002 ! -perm -1000 2>/dev/null | while read -r dir; do
                # Skip /tmp y /var/tmp que necesitan ser mundo escribibles
                if [[ "$dir" != "/tmp" && "$dir" != "/var/tmp" ]]; then
                    echo "log_fix \"Removiendo permisos de escritura mundial de $dir\"" >> "$FIX_SCRIPT"
                    echo "chmod o-w \"$dir\"" >> "$FIX_SCRIPT"
                fi
            done
        fi
    done
    
    echo -e "\necho \"Correcciones aplicadas exitosamente.\"" >> "$FIX_SCRIPT"
    
    chmod +x "$FIX_SCRIPT"
    log_message "SUCCESS" "Script de corrección generado: $FIX_SCRIPT"
}

# Aplicar correcciones automáticas
apply_fixes() {
    if [[ -x "$FIX_SCRIPT" ]]; then
        log_message "INFO" "Aplicando correcciones automáticas..."
        
        # Hacer backup antes de aplicar cambios
        local backup_dir="/tmp/perm_backup_$(date +%Y%m%d_%H%M%S)"
        mkdir -p "$backup_dir"
        
        # Ejecutar correcciones
        if bash "$FIX_SCRIPT" 2>&1 | tee -a "$LOG_FILE"; then
            log_message "SUCCESS" "Correcciones aplicadas exitosamente"
        else
            log_message "ERROR" "Algunas correcciones fallaron"
        fi
    else
        log_message "ERROR" "Script de corrección no encontrado o no ejecutable"
    fi
}

# ========================================
# FUNCIONES PRINCIPALES
# ========================================

# Ejecutar auditoría completa
run_audit() {
    log_message "INFO" "=== INICIANDO AUDITORÍA DE PERMISOS ==="
    
    # Inicializar reporte
    {
        echo "REPORTE DE AUDITORÍA DE PERMISOS"
        echo "================================"
        echo "Fecha: $(date)"
        echo "Sistema: $(hostname)"
        echo "Usuario: $(whoami)"
        echo ""
    } > "$REPORT_FILE"
    
    # Ejecutar auditorías
    audit_dangerous_permissions
    audit_critical_files
    audit_config_files
    audit_scripts
    
    # Generar resumen
    echo -e "\n=== RESUMEN EJECUTIVO ===" >> "$REPORT_FILE"
    local total_issues=$(grep -c "CRÍTICO\|ADVERTENCIA" "$REPORT_FILE" || echo "0")
    echo "Total de issues encontrados: $total_issues" >> "$REPORT_FILE"
    
    log_message "SUCCESS" "Auditoría completada. Reporte: $REPORT_FILE"
}

# Mostrar reporte
show_report() {
    if [[ -f "$REPORT_FILE" ]]; then
        cat "$REPORT_FILE"
    else
        log_message "ERROR" "Reporte no encontrado. Ejecuta primero la auditoría."
    fi
}

# Mostrar ayuda
show_help() {
    cat << EOF
Uso: $0 [COMANDO] [OPCIONES]

COMANDOS:
    audit           - Ejecutar auditoría completa de permisos
    report          - Mostrar último reporte generado
    fix             - Generar y aplicar correcciones automáticas
    generate-fix    - Solo generar script de corrección (sin aplicar)

OPCIONES:
    -v, --verbose   - Modo verbose
    -h, --help      - Mostrar esta ayuda

EJEMPLOS:
    $0 audit
    $0 fix
    $0 report

ARCHIVOS GENERADOS:
    - Reporte: $REPORT_FILE
    - Script de corrección: $FIX_SCRIPT
    - Log: $LOG_FILE
EOF
}

# ========================================
# FUNCIÓN PRINCIPAL
# ========================================

main() {
    check_root
    
    case "${1:-audit}" in
        audit)
            run_audit
            ;;
        report)
            show_report
            ;;
        fix)
            run_audit
            generate_fix_script
            apply_fixes
            ;;
        generate-fix)
            run_audit
            generate_fix_script
            ;;
        -h|--help|help)
            show_help
            exit 0
            ;;
        *)
            log_message "ERROR" "Comando desconocido: $1"
            show_help
            exit 1
            ;;
    esac
}

# Ejecutar si es llamado directamente
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi

Access Control Lists (ACLs)

Gestión Avanzada con ACLs

Los ACLs proporcionan un control de acceso más granular que los permisos tradicionales Unix.

acl_manager.sh Copiar
#!/bin/bash

# Gestor Avanzado de Access Control Lists (ACLs)
# Herramienta para gestionar permisos granulares

# ========================================
# CONFIGURACIÓN Y VARIABLES GLOBALES
# ========================================

readonly SCRIPT_NAME="$(basename "$0")"
readonly LOG_FILE="/var/log/acl_manager.log"

# Colores para output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'

# ========================================
# FUNCIONES DE UTILIDAD
# ========================================

log_message() {
    local level="$1"
    local message="$2"
    local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
    
    echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
    
    case "$level" in
        ERROR)   echo -e "${RED}[ERROR]${NC} $message" >&2 ;;
        WARNING) echo -e "${YELLOW}[WARNING]${NC} $message" >&2 ;;
        INFO)    echo -e "${BLUE}[INFO]${NC} $message" ;;
        SUCCESS) echo -e "${GREEN}[SUCCESS]${NC} $message" ;;
    esac
}

# Verificar si ACL está disponible
check_acl_support() {
    if ! command -v getfacl &> /dev/null || ! command -v setfacl &> /dev/null; then
        log_message "ERROR" "ACL tools no están instalados. Instala: apt-get install acl"
        exit 1
    fi
    
    # Verificar si el filesystem soporta ACL
    local test_file="/tmp/acl_test_$$"
    touch "$test_file"
    
    if ! setfacl -m u:root:r "$test_file" 2>/dev/null; then
        rm -f "$test_file"
        log_message "ERROR" "El filesystem no soporta ACLs o no está montado con opción 'acl'"
        exit 1
    fi
    
    rm -f "$test_file"
    log_message "SUCCESS" "Soporte ACL verificado"
}

# Validar usuario/grupo
validate_user_group() {
    local type="$1"  # user o group
    local name="$2"
    
    case "$type" in
        user)
            if ! id "$name" &>/dev/null; then
                log_message "ERROR" "Usuario no encontrado: $name"
                return 1
            fi
            ;;
        group)
            if ! getent group "$name" &>/dev/null; then
                log_message "ERROR" "Grupo no encontrado: $name"
                return 1
            fi
            ;;
        *)
            log_message "ERROR" "Tipo inválido: $type (debe ser user o group)"
            return 1
            ;;
    esac
    
    return 0
}

# Validar permisos
validate_permissions() {
    local perms="$1"
    
    if [[ ! "$perms" =~ ^[rwx-]+$ ]] || [[ ${#perms} -ne 3 ]]; then
        log_message "ERROR" "Formato de permisos inválido: $perms (usar formato rwx)"
        return 1
    fi
    
    return 0
}

# ========================================
# FUNCIONES DE GESTIÓN ACL
# ========================================

# Mostrar ACL de archivo/directorio
show_acl() {
    local target="$1"
    
    if [[ ! -e "$target" ]]; then
        log_message "ERROR" "Archivo/directorio no encontrado: $target"
        return 1
    fi
    
    log_message "INFO" "Mostrando ACL para: $target"
    
    echo -e "\n${BLUE}=== ACL para $target ===${NC}"
    getfacl "$target" 2>/dev/null || {
        log_message "ERROR" "No se pudo obtener ACL para $target"
        return 1
    }
    
    # Mostrar también permisos tradicionales para referencia
    echo -e "\n${BLUE}=== Permisos tradicionales ===${NC}"
    ls -la "$target"
}

# Establecer ACL para usuario
set_user_acl() {
    local target="$1"
    local username="$2"
    local permissions="$3"
    local recursive="${4:-false}"
    
    # Validaciones
    [[ ! -e "$target" ]] && { log_message "ERROR" "Target no encontrado: $target"; return 1; }
    validate_user_group "user" "$username" || return 1
    validate_permissions "$permissions" || return 1
    
    log_message "INFO" "Estableciendo ACL de usuario: $username:$permissions en $target"
    
    # Construcción del comando setfacl
    local setfacl_cmd="setfacl -m u:$username:$permissions"
    [[ "$recursive" == "true" ]] && setfacl_cmd="$setfacl_cmd -R"
    
    if $setfacl_cmd "$target"; then
        log_message "SUCCESS" "ACL establecido exitosamente"
        
        # Si es directorio y recursive, también establecer ACL por defecto
        if [[ -d "$target" && "$recursive" == "true" ]]; then
            if setfacl -m d:u:$username:$permissions "$target"; then
                log_message "SUCCESS" "ACL por defecto establecido para nuevos archivos"
            fi
        fi
        
        return 0
    else
        log_message "ERROR" "Falló al establecer ACL"
        return 1
    fi
}

# Establecer ACL para grupo
set_group_acl() {
    local target="$1"
    local groupname="$2"
    local permissions="$3"
    local recursive="${4:-false}"
    
    # Validaciones
    [[ ! -e "$target" ]] && { log_message "ERROR" "Target no encontrado: $target"; return 1; }
    validate_user_group "group" "$groupname" || return 1
    validate_permissions "$permissions" || return 1
    
    log_message "INFO" "Estableciendo ACL de grupo: $groupname:$permissions en $target"
    
    # Construcción del comando setfacl
    local setfacl_cmd="setfacl -m g:$groupname:$permissions"
    [[ "$recursive" == "true" ]] && setfacl_cmd="$setfacl_cmd -R"
    
    if $setfacl_cmd "$target"; then
        log_message "SUCCESS" "ACL de grupo establecido exitosamente"
        
        # Si es directorio y recursive, también establecer ACL por defecto
        if [[ -d "$target" && "$recursive" == "true" ]]; then
            if setfacl -m d:g:$groupname:$permissions "$target"; then
                log_message "SUCCESS" "ACL por defecto de grupo establecido"
            fi
        fi
        
        return 0
    else
        log_message "ERROR" "Falló al establecer ACL de grupo"
        return 1
    fi
}

# Remover ACL específico
remove_acl() {
    local target="$1"
    local type="$2"     # user o group
    local name="$3"
    local recursive="${4:-false}"
    
    [[ ! -e "$target" ]] && { log_message "ERROR" "Target no encontrado: $target"; return 1; }
    validate_user_group "$type" "$name" || return 1
    
    log_message "INFO" "Removiendo ACL de $type: $name en $target"
    
    local acl_entry=""
    case "$type" in
        user)  acl_entry="u:$name" ;;
        group) acl_entry="g:$name" ;;
    esac
    
    local setfacl_cmd="setfacl -x $acl_entry"
    [[ "$recursive" == "true" ]] && setfacl_cmd="$setfacl_cmd -R"
    
    if $setfacl_cmd "$target"; then
        log_message "SUCCESS" "ACL removido exitosamente"
        
        # Remover también ACL por defecto si existe
        if [[ -d "$target" ]]; then
            setfacl -x d:$acl_entry "$target" 2>/dev/null
        fi
        
        return 0
    else
        log_message "ERROR" "Falló al remover ACL"
        return 1
    fi
}

# Limpiar todos los ACLs
clear_all_acl() {
    local target="$1"
    local recursive="${2:-false}"
    
    [[ ! -e "$target" ]] && { log_message "ERROR" "Target no encontrado: $target"; return 1; }
    
    log_message "INFO" "Limpiando todos los ACLs de $target"
    
    local setfacl_cmd="setfacl -b"
    [[ "$recursive" == "true" ]] && setfacl_cmd="$setfacl_cmd -R"
    
    if $setfacl_cmd "$target"; then
        log_message "SUCCESS" "Todos los ACLs limpiados exitosamente"
        return 0
    else
        log_message "ERROR" "Falló al limpiar ACLs"
        return 1
    fi
}

# Copiar ACLs de un archivo a otro
copy_acl() {
    local source="$1"
    local destination="$2"
    
    [[ ! -e "$source" ]] && { log_message "ERROR" "Archivo fuente no encontrado: $source"; return 1; }
    [[ ! -e "$destination" ]] && { log_message "ERROR" "Archivo destino no encontrado: $destination"; return 1; }
    
    log_message "INFO" "Copiando ACLs de $source a $destination"
    
    # Obtener ACL del archivo fuente y aplicarlo al destino
    local temp_acl="/tmp/acl_copy_$$"
    
    if getfacl "$source" > "$temp_acl" 2>/dev/null; then
        if setfacl --restore="$temp_acl" 2>/dev/null; then
            log_message "SUCCESS" "ACLs copiados exitosamente"
            rm -f "$temp_acl"
            return 0
        else
            log_message "ERROR" "Falló al aplicar ACLs copiados"
            rm -f "$temp_acl"
            return 1
        fi
    else
        log_message "ERROR" "Falló al obtener ACLs del archivo fuente"
        return 1
    fi
}

# Backup de ACLs
backup_acl() {
    local target="$1"
    local backup_file="${2:-/tmp/acl_backup_$(date +%Y%m%d_%H%M%S).acl}"
    local recursive="${3:-false}"
    
    [[ ! -e "$target" ]] && { log_message "ERROR" "Target no encontrado: $target"; return 1; }
    
    log_message "INFO" "Creando backup de ACLs: $backup_file"
    
    local getfacl_cmd="getfacl"
    [[ "$recursive" == "true" ]] && getfacl_cmd="$getfacl_cmd -R"
    
    if $getfacl_cmd "$target" > "$backup_file" 2>/dev/null; then
        log_message "SUCCESS" "Backup de ACLs creado: $backup_file"
        echo "$backup_file"
        return 0
    else
        log_message "ERROR" "Falló al crear backup de ACLs"
        return 1
    fi
}

# Restaurar ACLs desde backup
restore_acl() {
    local backup_file="$1"
    
    [[ ! -f "$backup_file" ]] && { log_message "ERROR" "Archivo de backup no encontrado: $backup_file"; return 1; }
    
    log_message "INFO" "Restaurando ACLs desde: $backup_file"
    
    if setfacl --restore="$backup_file"; then
        log_message "SUCCESS" "ACLs restaurados exitosamente"
        return 0
    else
        log_message "ERROR" "Falló al restaurar ACLs"
        return 1
    fi
}

# Auditar ACLs en directorio
audit_acls() {
    local target_dir="$1"
    local report_file="/tmp/acl_audit_$(date +%Y%m%d_%H%M%S).txt"
    
    [[ ! -d "$target_dir" ]] && { log_message "ERROR" "Directorio no encontrado: $target_dir"; return 1; }
    
    log_message "INFO" "Auditando ACLs en: $target_dir"
    
    {
        echo "AUDITORÍA DE ACLs"
        echo "================="
        echo "Directorio: $target_dir"
        echo "Fecha: $(date)"
        echo ""
    } > "$report_file"
    
    # Buscar archivos con ACLs extendidos
    find "$target_dir" -type f -exec getfacl --skip-base {} + 2>/dev/null | grep -B1 -A10 "# file:" >> "$report_file"
    
    log_message "SUCCESS" "Auditoría completada. Reporte: $report_file"
    echo "$report_file"
}

# ========================================
# FUNCIÓN PRINCIPAL
# ========================================

show_help() {
    cat << EOF
Uso: $0 COMANDO [OPCIONES]

COMANDOS:
    show TARGET                          - Mostrar ACL de archivo/directorio
    set-user TARGET USER PERMS [--recursive] - Establecer ACL de usuario
    set-group TARGET GROUP PERMS [--recursive] - Establecer ACL de grupo
    remove TARGET TYPE NAME [--recursive] - Remover ACL específico
    clear TARGET [--recursive]          - Limpiar todos los ACLs
    copy SOURCE DESTINATION             - Copiar ACLs entre archivos
    backup TARGET [FILE] [--recursive]  - Crear backup de ACLs
    restore BACKUP_FILE                 - Restaurar ACLs desde backup
    audit DIRECTORY                     - Auditar ACLs en directorio

PARÁMETROS:
    TARGET      - Archivo o directorio objetivo
    USER/GROUP  - Nombre de usuario o grupo
    PERMS       - Permisos en formato rwx (ej: r-x, rw-, rwx)
    TYPE        - 'user' o 'group'

EJEMPLOS:
    $0 show /var/www/html
    $0 set-user /var/www/html developer rw- --recursive
    $0 set-group /shared/docs editors r-x
    $0 remove /var/www/html user developer --recursive
    $0 backup /important/data /tmp/data_acl.backup --recursive
    $0 audit /home
EOF
}

main() {
    [[ $# -eq 0 ]] && { show_help; exit 1; }
    
    check_acl_support
    
    local command="$1"
    shift
    
    case "$command" in
        show)
            [[ $# -lt 1 ]] && { log_message "ERROR" "Target requerido"; exit 1; }
            show_acl "$1"
            ;;
        set-user)
            [[ $# -lt 3 ]] && { log_message "ERROR" "Target, usuario y permisos requeridos"; exit 1; }
            local recursive=false
            [[ "$4" == "--recursive" ]] && recursive=true
            set_user_acl "$1" "$2" "$3" "$recursive"
            ;;
        set-group)
            [[ $# -lt 3 ]] && { log_message "ERROR" "Target, grupo y permisos requeridos"; exit 1; }
            local recursive=false
            [[ "$4" == "--recursive" ]] && recursive=true
            set_group_acl "$1" "$2" "$3" "$recursive"
            ;;
        remove)
            [[ $# -lt 3 ]] && { log_message "ERROR" "Target, tipo y nombre requeridos"; exit 1; }
            local recursive=false
            [[ "$4" == "--recursive" ]] && recursive=true
            remove_acl "$1" "$2" "$3" "$recursive"
            ;;
        clear)
            [[ $# -lt 1 ]] && { log_message "ERROR" "Target requerido"; exit 1; }
            local recursive=false
            [[ "$2" == "--recursive" ]] && recursive=true
            clear_all_acl "$1" "$recursive"
            ;;
        copy)
            [[ $# -lt 2 ]] && { log_message "ERROR" "Source y destination requeridos"; exit 1; }
            copy_acl "$1" "$2"
            ;;
        backup)
            [[ $# -lt 1 ]] && { log_message "ERROR" "Target requerido"; exit 1; }
            local recursive=false
            [[ "$3" == "--recursive" ]] && recursive=true
            backup_acl "$1" "$2" "$recursive"
            ;;
        restore)
            [[ $# -lt 1 ]] && { log_message "ERROR" "Archivo de backup requerido"; exit 1; }
            restore_acl "$1"
            ;;
        audit)
            [[ $# -lt 1 ]] && { log_message "ERROR" "Directorio requerido"; exit 1; }
            audit_acls "$1"
            ;;
        -h|--help|help)
            show_help
            exit 0
            ;;
        *)
            log_message "ERROR" "Comando desconocido: $command"
            show_help
            exit 1
            ;;
    esac
}

# Ejecutar si es llamado directamente
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi

Ejercicios Prácticos

Ejercicio 1: Implementación de Permisos Seguros

Desarrolla un sistema que:

  1. Audite permisos de un directorio web
  2. Identifique vulnerabilidades de seguridad
  3. Genere un plan de corrección automático
  4. Implemente ACLs granulares para diferentes roles
  5. Monitoree cambios de permisos en tiempo real
Proyecto Avanzado: Sistema de Control de Acceso Empresarial

Implementa una solución completa que incluya:

  • Políticas de permisos basadas en roles organizacionales
  • Sistema de auditoría y compliance automático
  • Integración con directorios LDAP/Active Directory
  • Alertas en tiempo real por violaciones de seguridad
  • Dashboard de monitoreo de permisos
Consideraciones Críticas de Seguridad
  • Principio de menor privilegio: Otorga solo los permisos mínimos necesarios
  • Revisión periódica: Audita permisos regularmente
  • Separación de roles: Diferentes niveles de acceso por función
  • Monitoreo continuo: Detecta cambios no autorizados
  • Backup de configuración: Mantén copias de seguridad de ACLs