Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Wichtiger Hinweis

Die in diesen Tutorials bereitgestellten Codebeispiele und Skripte dienen nur zu Bildungszwecken. Macfleet ist nicht verantwortlich für Probleme, Schäden oder Sicherheitslücken, die durch die Verwendung, Änderung oder Implementierung dieser Beispiele entstehen können. Überprüfen und testen Sie Code immer in einer sicheren Umgebung, bevor Sie ihn in Produktionssystemen verwenden.

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

Neue Updates und Verbesserungen zu Macfleet.

Konfiguration eines GitHub Actions Runners auf einem Mac Mini (Apple Silicon)

GitHub Actions Runner

GitHub Actions ist eine leistungsstarke CI/CD-Plattform, die es Ihnen ermöglicht, Ihre Software-Entwicklungsworkflows zu automatisieren. Während GitHub gehostete Runner anbietet, bieten selbst-gehostete Runner erhöhte Kontrolle und Anpassung für Ihr CI/CD-Setup. Dieses Tutorial führt Sie durch die Einrichtung, Konfiguration und Verbindung eines selbst-gehosteten Runners auf einem Mac mini zur Ausführung von macOS-Pipelines.

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie haben:

  • Einen Mac mini (registrieren Sie sich bei Macfleet)
  • Ein GitHub-Repository mit Administratorrechten
  • Einen installierten Paketmanager (vorzugsweise Homebrew)
  • Git auf Ihrem System installiert

Schritt 1: Ein dediziertes Benutzerkonto erstellen

Erstellen Sie zunächst ein dediziertes Benutzerkonto für den GitHub Actions Runner:

# Das 'gh-runner' Benutzerkonto erstellen
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

# Das Passwort für den Benutzer setzen
sudo dscl . -passwd /Users/gh-runner ihr_passwort

# 'gh-runner' zur 'admin'-Gruppe hinzufügen
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Wechseln Sie zum neuen Benutzerkonto:

su gh-runner

Schritt 2: Erforderliche Software installieren

Installieren Sie Git und Rosetta 2 (wenn Sie Apple Silicon verwenden):

# Git installieren, falls noch nicht installiert
brew install git

# Rosetta 2 für Apple Silicon Macs installieren
softwareupdate --install-rosetta

Schritt 3: Den GitHub Actions Runner konfigurieren

  1. Gehen Sie zu Ihrem GitHub-Repository
  2. Navigieren Sie zu Einstellungen > Actions > Runners

GitHub Actions Runner

  1. Klicken Sie auf "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Wählen Sie macOS als Runner-Image und ARM64 als Architektur
  3. Folgen Sie den bereitgestellten Befehlen, um den Runner herunterzuladen und zu konfigurieren

GitHub Actions Runner

Erstellen Sie eine .env-Datei im _work-Verzeichnis des Runners:

# _work/.env Datei
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Führen Sie das run.sh-Skript in Ihrem Runner-Verzeichnis aus, um die Einrichtung abzuschließen.
  2. Überprüfen Sie, dass der Runner aktiv ist und auf Jobs im Terminal wartet, und überprüfen Sie die GitHub-Repository-Einstellungen für die Runner-Zuordnung und den Idle-Status.

GitHub Actions Runner

Schritt 4: Sudoers konfigurieren (Optional)

Wenn Ihre Actions Root-Privilegien benötigen, konfigurieren Sie die sudoers-Datei:

sudo visudo

Fügen Sie die folgende Zeile hinzu:

gh-runner ALL=(ALL) NOPASSWD: ALL

Schritt 5: Den Runner in Workflows verwenden

Konfigurieren Sie Ihren GitHub Actions Workflow, um den selbst-gehosteten Runner zu verwenden:

name: Beispiel-Workflow

on:
  workflow_dispatch:

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

Der Runner ist bei Ihrem Repository authentifiziert und mit self-hosted, macOS und ARM64 markiert. Verwenden Sie ihn in Ihren Workflows, indem Sie diese Labels im runs-on-Feld angeben:

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

Best Practices

  • Halten Sie Ihre Runner-Software auf dem neuesten Stand
  • Überwachen Sie regelmäßig Runner-Logs auf Probleme
  • Verwenden Sie spezifische Labels für verschiedene Runner-Typen
  • Implementieren Sie angemessene Sicherheitsmaßnahmen
  • Erwägen Sie die Verwendung mehrerer Runner für Lastverteilung

Fehlerbehebung

Häufige Probleme und Lösungen:

  1. Runner verbindet sich nicht:

    • Überprüfen Sie die Netzwerkverbindung
    • Überprüfen Sie die Gültigkeit des GitHub-Tokens
    • Stellen Sie angemessene Berechtigungen sicher
  2. Build-Fehler:

    • Überprüfen Sie die Xcode-Installation
    • Überprüfen Sie erforderliche Abhängigkeiten
    • Überprüfen Sie Workflow-Logs
  3. Berechtigungsprobleme:

    • Überprüfen Sie Benutzerberechtigungen
    • Überprüfen Sie sudoers-Konfiguration
    • Überprüfen Sie Dateisystem-Berechtigungen

Fazit

Sie haben jetzt einen selbst-gehosteten GitHub Actions Runner auf Ihrem Mac mini konfiguriert. Diese Einrichtung bietet Ihnen mehr Kontrolle über Ihre CI/CD-Umgebung und ermöglicht es Ihnen, macOS-spezifische Workflows effizient auszuführen.

Denken Sie daran, Ihren Runner regelmäßig zu warten und ihn mit den neuesten Sicherheitspatches und Software-Versionen auf dem neuesten Stand zu halten.

Native App

Macfleet native App

Macfleet Installationsanleitung

Macfleet ist eine leistungsstarke Flottenmanagement-Lösung, die speziell für Cloud-gehostete Mac Mini-Umgebungen entwickelt wurde. Als Mac Mini Cloud-Hosting-Anbieter können Sie Macfleet verwenden, um Ihre gesamte Flotte virtualisierter Mac-Instanzen zu überwachen, zu verwalten und zu optimieren.

Diese Installationsanleitung führt Sie durch die Einrichtung der Macfleet-Überwachung auf macOS-, Windows- und Linux-Systemen, um eine umfassende Übersicht über Ihre Cloud-Infrastruktur zu gewährleisten.

🍎 macOS

  • Laden Sie die .dmg-Datei für Mac hier herunter
  • Doppelklicken Sie auf die heruntergeladene .dmg-Datei
  • Ziehen Sie die Macfleet-App in den Anwendungsordner
  • Werfen Sie die .dmg-Datei aus
  • Öffnen Sie Systemeinstellungen > Sicherheit & Datenschutz
    • Datenschutz-Tab > Bedienungshilfen
    • Aktivieren Sie Macfleet, um Überwachung zu erlauben
  • Starten Sie Macfleet aus den Anwendungen
  • Die Verfolgung startet automatisch

🪟 Windows

  • Laden Sie die .exe-Datei für Windows hier herunter
  • Rechtsklick auf die .exe-Datei > "Als Administrator ausführen"
  • Folgen Sie dem Installationsassistenten
  • Akzeptieren Sie die Allgemeinen Geschäftsbedingungen
  • Erlauben Sie in Windows Defender, wenn aufgefordert
  • Gewähren Sie Anwendungsüberwachungsberechtigungen
  • Starten Sie Macfleet aus dem Startmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

🐧 Linux

  • Laden Sie das .deb-Paket (Ubuntu/Debian) oder .rpm (CentOS/RHEL) hier herunter
  • Installieren Sie mit Ihrem Paketmanager
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Erlauben Sie X11-Zugriffsberechtigungen, wenn aufgefordert
  • Fügen Sie den Benutzer zu entsprechenden Gruppen hinzu, falls erforderlich
  • Starten Sie Macfleet aus dem Anwendungsmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

Hinweis: Nach der Installation auf allen Systemen melden Sie sich mit Ihren Macfleet-Anmeldedaten an, um Daten mit Ihrem Dashboard zu synchronisieren.