Tutorial

Novas atualizações e melhorias para a Macfleet.

Aviso importante

Os exemplos de código e scripts fornecidos nestes tutoriais são apenas para fins educacionais. A Macfleet não é responsável por quaisquer problemas, danos ou vulnerabilidades de segurança que possam surgir do uso, modificação ou implementação destes exemplos. Sempre revise e teste o código em um ambiente seguro antes de usá-lo em sistemas de produção.

Code Signature Analysis and Security on macOS

Analyze and manage application code signatures on your MacFleet devices to enhance security, verify application authenticity, and implement enterprise signing policies. This tutorial covers code requirement extraction, signature verification, and comprehensive security analysis.

Understanding macOS Code Signatures

Code signatures on macOS provide cryptographic verification that applications haven't been tampered with and come from trusted sources. Key components include:

  • Code Requirements - Constraints that code must satisfy to be considered valid
  • Bundle Identifiers - Unique identifiers for applications
  • Developer Certificates - Digital certificates used to sign applications
  • Entitlements - Permissions and capabilities granted to applications

Enterprise Security Importance

Code signature analysis is crucial for enterprise security:

  • Application Authenticity - Verify applications come from trusted developers
  • Tampering Detection - Identify modified or compromised applications
  • Privacy Policy Enforcement - Control access to protected user data
  • Compliance Requirements - Meet security standards for regulated industries
  • Malware Prevention - Block unauthorized or suspicious applications

Basic Code Signature Analysis

Extract Code Requirement

#!/bin/bash

# Basic code requirement extraction
APP_PATH="/System/Applications/Time Machine.app"

echo "Extracting code requirement for: $APP_PATH"
codesign -dr - "$APP_PATH"

Extract Code Requirement with Error Handling

#!/bin/bash

# Enhanced code requirement extraction with validation
extract_code_requirement() {
    local app_path="$1"
    
    # Validate input
    if [[ -z "$app_path" ]]; then
        echo "Error: No application path provided"
        echo "Usage: extract_code_requirement <app_path>"
        return 1
    fi
    
    # Check if application exists
    if [[ ! -e "$app_path" ]]; then
        echo "Error: Application not found at path: $app_path"
        return 1
    fi
    
    echo "=== Code Requirement Analysis ==="
    echo "Application: $app_path"
    echo ""
    
    # Extract code requirement
    local code_req
    code_req=$(codesign -dr - "$app_path" 2>&1)
    
    if [[ $? -eq 0 ]]; then
        echo "Code Requirement:"
        echo "$code_req"
        
        # Extract just the designated requirement
        local designated_req
        designated_req=$(echo "$code_req" | grep "designated =>" | sed 's/designated => //')
        
        if [[ -n "$designated_req" ]]; then
            echo ""
            echo "Designated Requirement:"
            echo "$designated_req"
        fi
    else
        echo "Error extracting code requirement:"
        echo "$code_req"
        return 1
    fi
}

# Usage examples
extract_code_requirement "/System/Applications/Safari.app"
extract_code_requirement "/Applications/Microsoft Word.app"

Comprehensive Application Analysis

#!/bin/bash

# Complete application signature analysis
analyze_application_signature() {
    local app_path="$1"
    local detailed="${2:-false}"
    
    if [[ ! -e "$app_path" ]]; then
        echo "Error: Application not found: $app_path"
        return 1
    fi
    
    echo "=== Complete Application Signature Analysis ==="
    echo "Application: $app_path"
    echo "Analysis Date: $(date)"
    echo ""
    
    # Basic information
    echo "--- Basic Information ---"
    if [[ -d "$app_path" ]]; then
        local bundle_id
        bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "Unknown")
        echo "Bundle ID: $bundle_id"
        
        local app_version
        app_version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "Unknown")
        echo "Version: $app_version"
    fi
    
    # Code signature verification
    echo ""
    echo "--- Code Signature Verification ---"
    if codesign -v "$app_path" 2>/dev/null; then
        echo "✓ Code signature is valid"
    else
        echo "⚠️ Code signature verification failed"
    fi
    
    # Detailed signature information
    echo ""
    echo "--- Signature Details ---"
    codesign -dv "$app_path" 2>&1
    
    # Code requirements
    echo ""
    echo "--- Code Requirements ---"
    codesign -dr - "$app_path" 2>&1
    
    # Entitlements (if detailed analysis requested)
    if [[ "$detailed" == "true" ]]; then
        echo ""
        echo "--- Entitlements ---"
        codesign -d --entitlements - "$app_path" 2>/dev/null || echo "No entitlements found"
    fi
    
    echo ""
    echo "=== Analysis Complete ==="
}

# Usage
analyze_application_signature "/Applications/Safari.app" "true"

Enterprise Code Signature Management

Batch Application Analysis

#!/bin/bash

# Analyze multiple applications for enterprise security review
batch_analyze_applications() {
    local scan_path="${1:-/Applications}"
    local output_format="${2:-table}"
    local include_system="${3:-false}"
    
    echo "=== Batch Application Signature Analysis ==="
    echo "Scan Path: $scan_path"
    echo "Include System Apps: $include_system"
    echo "Output Format: $output_format"
    echo ""
    
    local app_count=0
    local valid_count=0
    local invalid_count=0
    local results=()
    
    # Find all applications
    local find_paths=("$scan_path")
    if [[ "$include_system" == "true" ]]; then
        find_paths+=("/System/Applications" "/System/Library/CoreServices")
    fi
    
    for search_path in "${find_paths[@]}"; do
        if [[ -d "$search_path" ]]; then
            while IFS= read -r -d '' app_path; do
                ((app_count++))
                
                local app_name=$(basename "$app_path" .app)
                local bundle_id="Unknown"
                local signature_status="Invalid"
                local developer="Unknown"
                local code_req="Unknown"
                
                # Extract bundle ID
                if [[ -f "$app_path/Contents/Info.plist" ]]; then
                    bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "Unknown")
                fi
                
                # Check signature validity
                if codesign -v "$app_path" 2>/dev/null; then
                    signature_status="Valid"
                    ((valid_count++))
                    
                    # Extract developer information
                    local sig_info
                    sig_info=$(codesign -dv "$app_path" 2>&1)
                    developer=$(echo "$sig_info" | grep "Authority=" | head -1 | sed 's/Authority=//' | tr -d '\n')
                    
                    # Extract code requirement
                    code_req=$(codesign -dr - "$app_path" 2>/dev/null | grep "designated =>" | sed 's/designated => //')
                else
                    ((invalid_count++))
                fi
                
                # Store results
                results+=("$app_name|$bundle_id|$signature_status|$developer|$code_req")
                
                # Progress indicator
                if (( app_count % 10 == 0 )); then
                    echo "Analyzed $app_count applications..."
                fi
                
            done < <(find "$search_path" -name "*.app" -type d -print0 2>/dev/null)
        fi
    done
    
    echo ""
    echo "=== Analysis Summary ==="
    echo "Total Applications: $app_count"
    echo "Valid Signatures: $valid_count"
    echo "Invalid Signatures: $invalid_count"
    echo ""
    
    # Output results in requested format
    case "$output_format" in
        "table")
            printf "%-30s %-40s %-10s %-50s\n" "Application" "Bundle ID" "Signature" "Developer"
            printf "%-30s %-40s %-10s %-50s\n" "----------" "---------" "---------" "---------"
            
            for result in "${results[@]}"; do
                IFS='|' read -r app_name bundle_id sig_status developer code_req <<< "$result"
                printf "%-30s %-40s %-10s %-50s\n" \
                    "${app_name:0:29}" \
                    "${bundle_id:0:39}" \
                    "$sig_status" \
                    "${developer:0:49}"
            done
            ;;
        "csv")
            echo "Application,Bundle ID,Signature Status,Developer,Code Requirement"
            for result in "${results[@]}"; do
                echo "$result" | tr '|' ','
            done
            ;;
        "json")
            echo "{"
            echo "  \"analysis_summary\": {"
            echo "    \"total_applications\": $app_count,"
            echo "    \"valid_signatures\": $valid_count,"
            echo "    \"invalid_signatures\": $invalid_count,"
            echo "    \"scan_date\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
            echo "  },"
            echo "  \"applications\": ["
            
            local first=true
            for result in "${results[@]}"; do
                IFS='|' read -r app_name bundle_id sig_status developer code_req <<< "$result"
                
                if [[ "$first" == "true" ]]; then
                    first=false
                else
                    echo ","
                fi
                
                echo -n "    {"
                echo -n "\"name\": \"$app_name\", "
                echo -n "\"bundle_id\": \"$bundle_id\", "
                echo -n "\"signature_valid\": $([ "$sig_status" == "Valid" ] && echo "true" || echo "false"), "
                echo -n "\"developer\": \"$developer\", "
                echo -n "\"code_requirement\": \"$code_req\""
                echo -n "}"
            done
            
            echo ""
            echo "  ]"
            echo "}"
            ;;
    esac
}

# Usage examples
batch_analyze_applications "/Applications" "table" "false"
batch_analyze_applications "/Applications" "json" "true" > /tmp/app_analysis.json

Security Policy Enforcement

#!/bin/bash

# Enforce enterprise code signing policies
enforce_code_signing_policy() {
    local policy_name="$1"
    local action="${2:-report}"
    local target_path="${3:-/Applications}"
    
    echo "=== Enforcing Code Signing Policy: $policy_name ==="
    echo "Action: $action"
    echo "Target Path: $target_path"
    echo ""
    
    local violations=()
    local compliant_apps=()
    
    case "$policy_name" in
        "enterprise_strict")
            echo "Policy: Enterprise Strict - Only signed applications from trusted developers"
            
            # Define trusted developers
            local trusted_developers=(
                "Apple Inc."
                "Microsoft Corporation"
                "Adobe Inc."
                "Google LLC"
                "Zoom Video Communications, Inc."
            )
            
            check_enterprise_strict_policy "$target_path" trusted_developers violations compliant_apps
            ;;
        "apple_signed_only")
            echo "Policy: Apple Signed Only - Only Apple-signed applications allowed"
            check_apple_signed_policy "$target_path" violations compliant_apps
            ;;
        "no_unsigned")
            echo "Policy: No Unsigned - All applications must be signed"
            check_no_unsigned_policy "$target_path" violations compliant_apps
            ;;
        "developer_id_required")
            echo "Policy: Developer ID Required - All apps must have valid Developer ID"
            check_developer_id_policy "$target_path" violations compliant_apps
            ;;
        *)
            echo "Error: Unknown policy '$policy_name'"
            echo "Available policies: enterprise_strict, apple_signed_only, no_unsigned, developer_id_required"
            return 1
            ;;
    esac
    
    # Report results
    echo ""
    echo "=== Policy Enforcement Results ==="
    echo "Compliant Applications: ${#compliant_apps[@]}"
    echo "Policy Violations: ${#violations[@]}"
    
    if [[ ${#violations[@]} -gt 0 ]]; then
        echo ""
        echo "Policy Violations Found:"
        for violation in "${violations[@]}"; do
            echo "  ⚠️ $violation"
        done
    fi
    
    # Take action based on policy
    case "$action" in
        "report")
            echo ""
            echo "Action: Report Only - No changes made"
            generate_policy_report "$policy_name" violations compliant_apps
            ;;
        "quarantine")
            echo ""
            echo "Action: Quarantine - Moving violating applications"
            quarantine_violations violations
            ;;
        "remove")
            echo ""
            echo "Action: Remove - Deleting violating applications"
            remove_violations violations
            ;;
        *)
            echo "Error: Unknown action '$action'"
            ;;
    esac
}

# Check enterprise strict policy
check_enterprise_strict_policy() {
    local target_path="$1"
    local -n trusted_devs=$2
    local -n violations_ref=$3
    local -n compliant_ref=$4
    
    while IFS= read -r -d '' app_path; do
        local app_name=$(basename "$app_path")
        
        if codesign -v "$app_path" 2>/dev/null; then
            local developer
            developer=$(codesign -dv "$app_path" 2>&1 | grep "Authority=" | head -1 | sed 's/Authority=//')
            
            local is_trusted=false
            for trusted_dev in "${trusted_devs[@]}"; do
                if [[ "$developer" == *"$trusted_dev"* ]]; then
                    is_trusted=true
                    break
                fi
            done
            
            if [[ "$is_trusted" == "true" ]]; then
                compliant_ref+=("$app_name")
            else
                violations_ref+=("$app_name (Developer: $developer)")
            fi
        else
            violations_ref+=("$app_name (Unsigned)")
        fi
    done < <(find "$target_path" -name "*.app" -type d -print0 2>/dev/null)
}

# Check Apple-signed only policy
check_apple_signed_policy() {
    local target_path="$1"
    local -n violations_ref=$2
    local -n compliant_ref=$3
    
    while IFS= read -r -d '' app_path; do
        local app_name=$(basename "$app_path")
        
        if codesign -v "$app_path" 2>/dev/null; then
            local developer
            developer=$(codesign -dv "$app_path" 2>&1 | grep "Authority=" | head -1 | sed 's/Authority=//')
            
            if [[ "$developer" == *"Apple"* ]]; then
                compliant_ref+=("$app_name")
            else
                violations_ref+=("$app_name (Non-Apple Developer: $developer)")
            fi
        else
            violations_ref+=("$app_name (Unsigned)")
        fi
    done < <(find "$target_path" -name "*.app" -type d -print0 2>/dev/null)
}

# Generate policy compliance report
generate_policy_report() {
    local policy_name="$1"
    local -n violations_ref=$2
    local -n compliant_ref=$3
    
    local report_file="/tmp/code_signing_policy_report_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$report_file" << EOF
{
    "code_signing_policy_report": {
        "policy_name": "$policy_name",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "summary": {
            "total_applications": $((${#violations_ref[@]} + ${#compliant_ref[@]})),
            "compliant_applications": ${#compliant_ref[@]},
            "policy_violations": ${#violations_ref[@]},
            "compliance_percentage": $(( ${#compliant_ref[@]} * 100 / (${#violations_ref[@]} + ${#compliant_ref[@]}) ))
        },
        "violations": [
EOF
    
    local first=true
    for violation in "${violations_ref[@]}"; do
        if [[ "$first" == "true" ]]; then
            first=false
        else
            echo "," >> "$report_file"
        fi
        echo -n "            \"$violation\"" >> "$report_file"
    done
    
    cat >> "$report_file" << EOF

        ],
        "compliant_applications": [
EOF
    
    first=true
    for compliant in "${compliant_ref[@]}"; do
        if [[ "$first" == "true" ]]; then
            first=false
        else
            echo "," >> "$report_file"
        fi
        echo -n "            \"$compliant\"" >> "$report_file"
    done
    
    cat >> "$report_file" << EOF

        ]
    }
}
EOF
    
    echo "Policy report generated: $report_file"
}

# Usage
enforce_code_signing_policy "enterprise_strict" "report" "/Applications"

Enterprise Code Signature Management System

#!/bin/bash

# MacFleet Code Signature Management Tool
# Comprehensive code signature analysis and security policy enforcement

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_codesigning.log"
REPORT_DIR="/etc/macfleet/reports/codesigning"
CONFIG_DIR="/etc/macfleet/codesigning"
POLICY_DIR="/etc/macfleet/policies/codesigning"
QUARANTINE_DIR="/var/quarantine/applications"

# Create directories if they don't exist
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$POLICY_DIR" "$QUARANTINE_DIR"

# Code signing policy templates
declare -A SIGNING_POLICIES=(
    ["enterprise_standard"]="signed_required,developer_id_preferred,apple_signed_trusted,third_party_review"
    ["enterprise_strict"]="apple_signed_only,developer_id_required,no_unsigned,enterprise_review"
    ["development"]="signed_preferred,developer_id_optional,self_signed_allowed,minimal_restrictions"
    ["kiosk_lockdown"]="apple_signed_only,no_third_party,system_apps_only,maximum_security"
    ["healthcare"]="apple_signed_required,enterprise_approved_only,no_unsigned,hipaa_compliant"
    ["financial"]="apple_signed_required,enterprise_certified_only,strict_validation,sox_compliant"
    ["education"]="signed_required,educational_approved,apple_preferred,moderate_security"
    ["government"]="apple_signed_only,government_approved,no_unsigned,maximum_security"
    ["retail"]="signed_required,pos_approved,apple_preferred,moderate_security"
    ["manufacturing"]="signed_required,industrial_approved,apple_preferred,operational_security"
)

# Trusted developer registry
declare -A TRUSTED_DEVELOPERS=(
    ["apple"]="Apple Inc.,Software Signing,Apple Mac OS Application Signing"
    ["microsoft"]="Microsoft Corporation,Microsoft Corporation"
    ["adobe"]="Adobe Inc.,Adobe Systems Incorporated"
    ["google"]="Google LLC,Google Inc."
    ["zoom"]="Zoom Video Communications, Inc."
    ["slack"]="Slack Technologies, Inc."
    ["dropbox"]="Dropbox, Inc."
    ["1password"]="AgileBits Inc."
    ["firefox"]="Mozilla Corporation"
    ["chrome"]="Google LLC"
)

# Security classification levels
declare -A SECURITY_LEVELS=(
    ["maximum"]="apple_signed_only,no_exceptions,immediate_quarantine"
    ["high"]="signed_required,trusted_developers_only,review_required"
    ["medium"]="signed_preferred,warnings_enabled,monitoring_active"
    ["low"]="unsigned_allowed,notification_only,basic_monitoring"
)

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

# Advanced code signature analysis
analyze_code_signature() {
    local app_path="$1"
    local output_format="${2:-detailed}"
    local security_check="${3:-true}"
    
    log_action "Analyzing code signature for: $app_path"
    
    if [[ ! -e "$app_path" ]]; then
        log_action "ERROR: Application not found: $app_path"
        return 1
    fi
    
    local analysis_data=()
    local app_name=$(basename "$app_path" .app)
    
    echo "=== Advanced Code Signature Analysis ==="
    echo "Application: $app_name"
    echo "Path: $app_path"
    echo "Analysis Date: $(date)"
    echo ""
    
    # Basic application information
    extract_app_metadata "$app_path" analysis_data
    
    # Code signature verification
    verify_code_signature "$app_path" analysis_data
    
    # Extract code requirements
    extract_code_requirements "$app_path" analysis_data
    
    # Security analysis
    if [[ "$security_check" == "true" ]]; then
        perform_security_analysis "$app_path" analysis_data
    fi
    
    # Generate output in requested format
    case "$output_format" in
        "detailed")
            display_detailed_analysis analysis_data
            ;;
        "summary")
            display_summary_analysis analysis_data
            ;;
        "json")
            generate_json_analysis "$app_path" analysis_data
            ;;
        "csv")
            generate_csv_analysis "$app_path" analysis_data
            ;;
    esac
    
    log_action "Code signature analysis completed for: $app_path"
}

# Extract application metadata
extract_app_metadata() {
    local app_path="$1"
    local -n data_ref=$2
    
    echo "--- Application Metadata ---"
    
    if [[ -f "$app_path/Contents/Info.plist" ]]; then
        local bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "Unknown")
        local version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "Unknown")
        local build=$(defaults read "$app_path/Contents/Info.plist" CFBundleVersion 2>/dev/null || echo "Unknown")
        local min_os=$(defaults read "$app_path/Contents/Info.plist" LSMinimumSystemVersion 2>/dev/null || echo "Unknown")
        
        echo "Bundle ID: $bundle_id"
        echo "Version: $version"
        echo "Build: $build"
        echo "Minimum OS: $min_os"
        
        data_ref+=("bundle_id:$bundle_id")
        data_ref+=("version:$version")
        data_ref+=("build:$build")
        data_ref+=("min_os:$min_os")
    else
        echo "No Info.plist found"
        data_ref+=("bundle_id:Unknown")
    fi
    
    # File size and modification date
    local file_size=$(du -sh "$app_path" | cut -f1)
    local mod_date=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$app_path")
    
    echo "Application Size: $file_size"
    echo "Last Modified: $mod_date"
    
    data_ref+=("size:$file_size")
    data_ref+=("modified:$mod_date")
}

# Verify code signature
verify_code_signature() {
    local app_path="$1"
    local -n data_ref=$2
    
    echo ""
    echo "--- Code Signature Verification ---"
    
    # Basic verification
    if codesign -v "$app_path" 2>/dev/null; then
        echo "✓ Code signature is valid"
        data_ref+=("signature_valid:true")
        
        # Detailed signature information
        local sig_info=$(codesign -dv "$app_path" 2>&1)
        
        # Extract key information
        local identifier=$(echo "$sig_info" | grep "Identifier=" | sed 's/Identifier=//')
        local format=$(echo "$sig_info" | grep "Format=" | sed 's/Format=//')
        local cdhash=$(echo "$sig_info" | grep "CDHash=" | sed 's/CDHash=//')
        local team_id=$(echo "$sig_info" | grep "TeamIdentifier=" | sed 's/TeamIdentifier=//')
        
        echo "Identifier: $identifier"
        echo "Format: $format"
        echo "CDHash: $cdhash"
        echo "Team ID: $team_id"
        
        data_ref+=("identifier:$identifier")
        data_ref+=("format:$format")
        data_ref+=("cdhash:$cdhash")
        data_ref+=("team_id:$team_id")
        
        # Extract certificate chain
        local authorities=$(echo "$sig_info" | grep "Authority=" | sed 's/Authority=//')
        echo "Certificate Chain:"
        while IFS= read -r authority; do
            echo "  - $authority"
        done <<< "$authorities"
        
        data_ref+=("authorities:$authorities")
        
    else
        echo "⚠️ Code signature verification FAILED"
        data_ref+=("signature_valid:false")
        
        local error=$(codesign -v "$app_path" 2>&1)
        echo "Error: $error"
        data_ref+=("signature_error:$error")
    fi
}

# Extract code requirements
extract_code_requirements() {
    local app_path="$1"
    local -n data_ref=$2
    
    echo ""
    echo "--- Code Requirements ---"
    
    local req_output=$(codesign -dr - "$app_path" 2>&1)
    
    if [[ $? -eq 0 ]]; then
        echo "$req_output"
        
        # Extract designated requirement
        local designated_req=$(echo "$req_output" | grep "designated =>" | sed 's/designated => //')
        if [[ -n "$designated_req" ]]; then
            echo ""
            echo "Designated Requirement:"
            echo "$designated_req"
            data_ref+=("designated_requirement:$designated_req")
        fi
        
        data_ref+=("requirements_extracted:true")
    else
        echo "Failed to extract code requirements"
        echo "$req_output"
        data_ref+=("requirements_extracted:false")
    fi
}

# Perform security analysis
perform_security_analysis() {
    local app_path="$1"
    local -n data_ref=$2
    
    echo ""
    echo "--- Security Analysis ---"
    
    local security_score=100
    local security_issues=()
    
    # Check if application is signed
    if ! codesign -v "$app_path" 2>/dev/null; then
        security_score=$((security_score - 50))
        security_issues+=("Application is not signed")
    fi
    
    # Check for hardened runtime
    local flags=$(codesign -dv "$app_path" 2>&1 | grep "CodeDirectory" | grep "runtime")
    if [[ -n "$flags" ]]; then
        echo "✓ Hardened runtime enabled"
        data_ref+=("hardened_runtime:true")
    else
        echo "⚠️ Hardened runtime not enabled"
        security_score=$((security_score - 20))
        security_issues+=("Hardened runtime not enabled")
        data_ref+=("hardened_runtime:false")
    fi
    
    # Check for notarization
    if spctl -a -v "$app_path" 2>&1 | grep -q "notarized"; then
        echo "✓ Application is notarized"
        data_ref+=("notarized:true")
    else
        echo "⚠️ Application is not notarized"
        security_score=$((security_score - 15))
        security_issues+=("Application not notarized")
        data_ref+=("notarized:false")
    fi
    
    # Check for known vulnerabilities (basic check)
    check_known_vulnerabilities "$app_path" security_score security_issues
    
    echo ""
    echo "Security Score: $security_score/100"
    data_ref+=("security_score:$security_score")
    
    if [[ ${#security_issues[@]} -gt 0 ]]; then
        echo "Security Issues Found:"
        for issue in "${security_issues[@]}"; do
            echo "  ⚠️ $issue"
        done
        data_ref+=("security_issues:${security_issues[*]}")
    else
        echo "✓ No security issues found"
        data_ref+=("security_issues:none")
    fi
}

# Check for known vulnerabilities
check_known_vulnerabilities() {
    local app_path="$1"
    local -n score_ref=$2
    local -n issues_ref=$3
    
    local bundle_id
    bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "Unknown")
    
    # Check against known vulnerable applications (simplified example)
    case "$bundle_id" in
        "com.adobe.flashplayer"*)
            score_ref=$((score_ref - 30))
            issues_ref+=("Flash Player has known security vulnerabilities")
            ;;
        "com.java."*)
            # Check Java version for known vulnerabilities
            local java_version
            java_version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null)
            if [[ -n "$java_version" ]]; then
                echo "Java version detected: $java_version"
                # Add specific version checks here
            fi
            ;;
    esac
    
    # Check for applications with expired certificates
    local cert_info=$(codesign -dv "$app_path" 2>&1 | grep "Timestamp=")
    if [[ -n "$cert_info" ]]; then
        # Extract timestamp and check if certificate is old
        local timestamp=$(echo "$cert_info" | sed 's/Timestamp=//')
        echo "Certificate timestamp: $timestamp"
    fi
}

# Generate comprehensive fleet analysis
analyze_fleet_applications() {
    local scan_paths=("$@")
    local report_file="$REPORT_DIR/fleet_analysis_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Fleet-Wide Application Analysis ==="
    echo "Scanning paths: ${scan_paths[*]}"
    echo ""
    
    local total_apps=0
    local signed_apps=0
    local unsigned_apps=0
    local notarized_apps=0
    local security_issues=0
    local applications=()
    
    for scan_path in "${scan_paths[@]}"; do
        if [[ -d "$scan_path" ]]; then
            echo "Scanning: $scan_path"
            
            while IFS= read -r -d '' app_path; do
                ((total_apps++))
                
                local app_name=$(basename "$app_path" .app)
                local analysis_data=()
                
                # Quick analysis for fleet overview
                analyze_code_signature "$app_path" "summary" "true" > /dev/null
                
                # Extract key metrics
                if codesign -v "$app_path" 2>/dev/null; then
                    ((signed_apps++))
                else
                    ((unsigned_apps++))
                fi
                
                if spctl -a -v "$app_path" 2>&1 | grep -q "notarized"; then
                    ((notarized_apps++))
                fi
                
                # Add to applications array
                applications+=("$app_path")
                
                # Progress indicator
                if (( total_apps % 25 == 0 )); then
                    echo "Analyzed $total_apps applications..."
                fi
                
            done < <(find "$scan_path" -name "*.app" -type d -maxdepth 2 -print0 2>/dev/null)
        fi
    done
    
    # Generate fleet analysis report
    cat > "$report_file" << EOF
{
    "fleet_analysis": {
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "scan_paths": [$(printf '"%s",' "${scan_paths[@]}" | sed 's/,$//')],
        "summary": {
            "total_applications": $total_apps,
            "signed_applications": $signed_apps,
            "unsigned_applications": $unsigned_apps,
            "notarized_applications": $notarized_apps,
            "signing_compliance": $(( signed_apps * 100 / total_apps )),
            "notarization_compliance": $(( notarized_apps * 100 / total_apps ))
        },
        "analysis_date": "$(date)",
        "script_version": "$SCRIPT_VERSION"
    }
}
EOF
    
    echo ""
    echo "=== Fleet Analysis Summary ==="
    echo "Total Applications: $total_apps"
    echo "Signed Applications: $signed_apps ($(( signed_apps * 100 / total_apps ))%)"
    echo "Unsigned Applications: $unsigned_apps ($(( unsigned_apps * 100 / total_apps ))%)"
    echo "Notarized Applications: $notarized_apps ($(( notarized_apps * 100 / total_apps ))%)"
    echo ""
    echo "Fleet analysis report: $report_file"
    
    log_action "Fleet analysis completed: $total_apps applications analyzed"
}

# Main execution function
main() {
    local action="${1:-help}"
    local param1="${2:-}"
    local param2="${3:-}"
    local param3="${4:-}"
    local param4="${5:-}"
    
    log_action "=== MacFleet Code Signature Management Started ==="
    log_action "Action: $action"
    
    case "$action" in
        "analyze")
            if [[ -z "$param1" ]]; then
                echo "Usage: $0 analyze <app_path> [output_format] [security_check]"
                echo "Output formats: detailed, summary, json, csv"
                exit 1
            fi
            analyze_code_signature "$param1" "${param2:-detailed}" "${param3:-true}"
            ;;
        "extract")
            if [[ -z "$param1" ]]; then
                echo "Usage: $0 extract <app_path>"
                exit 1
            fi
            extract_code_requirement "$param1"
            ;;
        "batch")
            if [[ -z "$param1" ]]; then
                param1="/Applications"
            fi
            batch_analyze_applications "$param1" "${param2:-table}" "${param3:-false}"
            ;;
        "policy")
            if [[ -z "$param1" ]]; then
                echo "Available policies: ${!SIGNING_POLICIES[*]}"
                exit 1
            fi
            enforce_code_signing_policy "$param1" "${param2:-report}" "${param3:-/Applications}"
            ;;
        "fleet")
            local paths=("${@:2}")
            if [[ ${#paths[@]} -eq 0 ]]; then
                paths=("/Applications" "/System/Applications")
            fi
            analyze_fleet_applications "${paths[@]}"
            ;;
        "verify")
            if [[ -z "$param1" ]]; then
                echo "Usage: $0 verify <app_path>"
                exit 1
            fi
            if codesign -v "$param1" 2>/dev/null; then
                echo "✓ Code signature is valid for: $param1"
            else
                echo "⚠️ Code signature verification failed for: $param1"
                codesign -v "$param1"
            fi
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  analyze <app_path> [format] [security] - Analyze application signature"
            echo "  extract <app_path> - Extract code requirement only"
            echo "  batch <scan_path> [format] [include_system] - Batch analyze applications"
            echo "  policy <policy_name> [action] [path] - Enforce signing policy"
            echo "  fleet [paths...] - Analyze fleet-wide applications"
            echo "  verify <app_path> - Quick signature verification"
            echo "  help - Show this help"
            echo ""
            echo "Output Formats: detailed, summary, json, csv, table"
            echo "Policies: ${!SIGNING_POLICIES[*]}"
            echo "Security Levels: ${!SECURITY_LEVELS[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action"
            echo "Use '$0 help' for usage information"
            exit 1
            ;;
    esac
    
    log_action "=== Code signature management completed ==="
}

# Execute main function
main "$@"

Security Best Practices

Enterprise Certificate Management

#!/bin/bash

# Enterprise certificate validation
validate_enterprise_certificates() {
    local cert_policy="${1:-strict}"
    
    echo "=== Enterprise Certificate Validation ==="
    echo "Policy: $cert_policy"
    echo ""
    
    local expired_certs=()
    local revoked_certs=()
    local untrusted_certs=()
    
    # Check system keychain for enterprise certificates
    security find-certificate -a -p /Library/Keychains/System.keychain | \
    while IFS= read -r cert_line; do
        if [[ "$cert_line" == "-----BEGIN CERTIFICATE-----" ]]; then
            # Process certificate
            echo "Checking enterprise certificate..."
        fi
    done
    
    echo "✓ Enterprise certificate validation completed"
}

validate_enterprise_certificates "strict"

Compliance Reporting

#!/bin/bash

# Generate compliance report for regulatory requirements
generate_compliance_report() {
    local compliance_type="${1:-general}"
    local output_file="$REPORT_DIR/compliance_${compliance_type}_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Compliance Report: $compliance_type ==="
    
    local total_apps=0
    local compliant_apps=0
    local non_compliant_apps=0
    
    # Scan applications for compliance
    while IFS= read -r -d '' app_path; do
        ((total_apps++))
        
        case "$compliance_type" in
            "hipaa")
                check_hipaa_compliance "$app_path" compliant_apps non_compliant_apps
                ;;
            "sox")
                check_sox_compliance "$app_path" compliant_apps non_compliant_apps
                ;;
            "pci_dss")
                check_pci_compliance "$app_path" compliant_apps non_compliant_apps
                ;;
            *)
                check_general_compliance "$app_path" compliant_apps non_compliant_apps
                ;;
        esac
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    # Generate report
    local compliance_percentage=$(( compliant_apps * 100 / total_apps ))
    
    cat > "$output_file" << EOF
{
    "compliance_report": {
        "type": "$compliance_type",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "summary": {
            "total_applications": $total_apps,
            "compliant_applications": $compliant_apps,
            "non_compliant_applications": $non_compliant_apps,
            "compliance_percentage": $compliance_percentage
        }
    }
}
EOF
    
    echo "Compliance report generated: $output_file"
    echo "Compliance rate: $compliance_percentage%"
}

generate_compliance_report "general"

Important Notes

  • Code signatures verify application authenticity and integrity
  • Code requirements specify constraints for application validation
  • Enterprise policies should balance security with operational needs
  • Regular monitoring helps detect unauthorized applications
  • Compliance requirements vary by industry and regulatory framework
  • Notarization provides additional security validation from Apple
  • Certificate management is crucial for enterprise security
  • Fleet-wide analysis enables proactive security management

Tutorial

Novas atualizações e melhorias para a Macfleet.

Configurando um Runner do GitHub Actions em um Mac Mini (Apple Silicon)

Runner do GitHub Actions

GitHub Actions é uma plataforma poderosa de CI/CD que permite automatizar seus fluxos de trabalho de desenvolvimento de software. Embora o GitHub ofereça runners hospedados, runners auto-hospedados fornecem maior controle e personalização para sua configuração de CI/CD. Este tutorial o guia através da configuração e conexão de um runner auto-hospedado em um Mac mini para executar pipelines do macOS.

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Um Mac mini (registre-se no Macfleet)
  • Um repositório GitHub com direitos de administrador
  • Um gerenciador de pacotes instalado (preferencialmente Homebrew)
  • Git instalado em seu sistema

Passo 1: Criar uma Conta de Usuário Dedicada

Primeiro, crie uma conta de usuário dedicada para o runner do GitHub Actions:

# Criar a conta de usuário '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

# Definir a senha para o usuário
sudo dscl . -passwd /Users/gh-runner sua_senha

# Adicionar 'gh-runner' ao grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Mude para a nova conta de usuário:

su gh-runner

Passo 2: Instalar Software Necessário

Instale Git e Rosetta 2 (se estiver usando Apple Silicon):

# Instalar Git se ainda não estiver instalado
brew install git

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

Passo 3: Configurar o Runner do GitHub Actions

  1. Vá para seu repositório GitHub
  2. Navegue para Configurações > Actions > Runners

Runner do GitHub Actions

  1. Clique em "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecione macOS como imagem do runner e ARM64 como arquitetura
  3. Siga os comandos fornecidos para baixar e configurar o runner

Runner do GitHub Actions

Crie um arquivo .env no diretório _work do runner:

# arquivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Execute o script run.sh em seu diretório do runner para completar a configuração.
  2. Verifique se o runner está ativo e ouvindo por trabalhos no terminal e verifique as configurações do repositório GitHub para a associação do runner e status Idle.

Runner do GitHub Actions

Passo 4: Configurar Sudoers (Opcional)

Se suas ações requerem privilégios de root, configure o arquivo sudoers:

sudo visudo

Adicione a seguinte linha:

gh-runner ALL=(ALL) NOPASSWD: ALL

Passo 5: Usar o Runner em Fluxos de Trabalho

Configure seu fluxo de trabalho do GitHub Actions para usar o runner auto-hospedado:

name: Fluxo de trabalho de exemplo

on:
  workflow_dispatch:

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

O runner está autenticado em seu repositório e rotulado com self-hosted, macOS, e ARM64. Use-o em seus fluxos de trabalho especificando estes rótulos no campo runs-on:

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

Melhores Práticas

  • Mantenha seu software do runner atualizado
  • Monitore regularmente os logs do runner para problemas
  • Use rótulos específicos para diferentes tipos de runners
  • Implemente medidas de segurança adequadas
  • Considere usar múltiplos runners para balanceamento de carga

Solução de Problemas

Problemas comuns e soluções:

  1. Runner não conectando:

    • Verifique conectividade de rede
    • Verifique validade do token GitHub
    • Certifique-se de permissões adequadas
  2. Falhas de build:

    • Verifique instalação do Xcode
    • Verifique dependências necessárias
    • Revise logs do fluxo de trabalho
  3. Problemas de permissão:

    • Verifique permissões do usuário
    • Verifique configuração sudoers
    • Revise permissões do sistema de arquivos

Conclusão

Agora você tem um runner auto-hospedado do GitHub Actions configurado em seu Mac mini. Esta configuração fornece mais controle sobre seu ambiente CI/CD e permite executar fluxos de trabalho específicos do macOS de forma eficiente.

Lembre-se de manter regularmente seu runner e mantê-lo atualizado com os patches de segurança e versões de software mais recentes.

Aplicativo Nativo

Aplicativo nativo do Macfleet

Guia de Instalação do Macfleet

Macfleet é uma solução poderosa de gerenciamento de frota projetada especificamente para ambientes Mac Mini hospedados na nuvem. Como provedor de hospedagem na nuvem Mac Mini, você pode usar o Macfleet para monitorar, gerenciar e otimizar toda sua frota de instâncias Mac virtualizadas.

Este guia de instalação o conduzirá através da configuração do monitoramento do Macfleet em sistemas macOS, Windows e Linux para garantir supervisão abrangente de sua infraestrutura na nuvem.

🍎 macOS

  • Baixe o arquivo .dmg para Mac aqui
  • Clique duas vezes no arquivo .dmg baixado
  • Arraste o aplicativo Macfleet para a pasta Aplicativos
  • Ejete o arquivo .dmg
  • Abra Preferências do Sistema > Segurança e Privacidade
    • Aba Privacidade > Acessibilidade
    • Marque Macfleet para permitir monitoramento
  • Inicie o Macfleet a partir de Aplicativos
  • O rastreamento inicia automaticamente

🪟 Windows

  • Baixe o arquivo .exe para Windows aqui
  • Clique com o botão direito no arquivo .exe > "Executar como administrador"
  • Siga o assistente de instalação
  • Aceite os termos e condições
  • Permita no Windows Defender se solicitado
  • Conceda permissões de monitoramento de aplicativo
  • Inicie o Macfleet a partir do Menu Iniciar
  • O aplicativo começa o rastreamento automaticamente

🐧 Linux

  • Baixe o pacote .deb (Ubuntu/Debian) ou .rpm (CentOS/RHEL) aqui
  • Instale usando seu gerenciador de pacotes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permita permissões de acesso X11 se solicitado
  • Adicione o usuário aos grupos apropriados se necessário
  • Inicie o Macfleet a partir do menu Aplicativos
  • O aplicativo começa o rastreamento automaticamente

Nota: Após a instalação em todos os sistemas, faça login com suas credenciais do Macfleet para sincronizar dados com seu painel de controle.