FileVault Key Rotation ๐
ืชืืื ืื ืืื ื ืืืื ืขืืืื ืืฉืคื ืฉืื.
FileVault Key Rotation ๐
Section titled โFileVault Key Rotation ๐โOverview
Section titled โOverviewโThis PowerShell script provides automated FileVault recovery key rotation for macOS devices managed through Microsoft Intune. The script enhances security by regularly rotating FileVault recovery keys while maintaining proper audit trails and backup procedures.
Prerequisites
Section titled โPrerequisitesโSystem Requirements
Section titled โSystem Requirementsโ- macOS: 10.15 (Catalina) or later
- Microsoft Intune: Device management and script deployment
- PowerShell: 7.0 or later for cross-platform compatibility
- Administrator Privileges: Required for FileVault operations
Dependencies
Section titled โDependenciesโ- FileVault: Must be enabled on target devices
- Intune Management: Device enrolled in Intune
- Secure Storage: Encrypted location for key backup
- Logging Infrastructure: Centralized logging system
Script Configuration
Section titled โScript ConfigurationโParameters
Section titled โParametersโparam( [Parameter(Mandatory=$false)] [string]$KeyBackupLocation = "/var/log/filevault-keys",
[Parameter(Mandatory=$false)] [string]$LogPath = "/var/log/filevault-rotation.log",
[Parameter(Mandatory=$false)] [int]$KeyRetentionDays = 90,
[Parameter(Mandatory=$false)] [switch]$ForceRotation = $false,
[Parameter(Mandatory=$false)] [switch]$TestMode = $false)Global Variables
Section titled โGlobal Variablesโ# Configuration settings$ScriptVersion = "2.1.0"$CompanyName = "YourCompany"$SupportEmail = "support@yourcompany.com"$MaxRotationAttempts = 3$RotationIntervalDays = 30Script Implementation
Section titled โScript ImplementationโMain Function
Section titled โMain Functionโfunction Start-FileVaultKeyRotation { param( [string]$BackupPath, [string]$LogPath, [int]$RetentionDays, [bool]$Force, [bool]$Test )
try { # Initialize logging Initialize-Logging -LogPath $LogPath
Write-Log "Starting FileVault key rotation - Version $ScriptVersion" Write-Log "Parameters: BackupPath=$BackupPath, RetentionDays=$RetentionDays, Force=$Force, Test=$Test"
# Check prerequisites if (-not (Test-Prerequisites)) { Write-Log "Prerequisites check failed" -Level "ERROR" return $false }
# Get current FileVault status $fVaultStatus = Get-FileVaultStatus if (-not $fVaultStatus.Enabled) { Write-Log "FileVault is not enabled on this device" -Level "WARNING" return $false }
# Check if rotation is needed if (-not $Force -and -not (Test-RotationNeeded -LastRotation $fVaultStatus.LastRotation)) { Write-Log "Key rotation not needed at this time" return $true }
# Perform key rotation $rotationResult = Invoke-KeyRotation -TestMode $Test if ($rotationResult.Success) { Write-Log "Key rotation completed successfully"
# Backup new key $backupResult = Backup-RecoveryKey -Key $rotationResult.NewKey -BackupPath $BackupPath if ($backupResult.Success) { Write-Log "Recovery key backed up successfully" } else { Write-Log "Failed to backup recovery key" -Level "ERROR" }
# Clean up old keys Remove-OldKeys -RetentionDays $RetentionDays -BackupPath $BackupPath
return $true } else { Write-Log "Key rotation failed: $($rotationResult.ErrorMessage)" -Level "ERROR" return $false }
} catch { Write-Log "Unexpected error in Start-FileVaultKeyRotation: $($_.Exception.Message)" -Level "ERROR" return $false }}Helper Functions
Section titled โHelper FunctionsโPrerequisites Check
Section titled โPrerequisites Checkโfunction Test-Prerequisites { try { # Check if running on macOS if ($PSVersionTable.Platform -ne "Unix" -or $env:OS -ne "Darwin") { Write-Log "This script must be run on macOS" -Level "ERROR" return $false }
# Check FileVault availability $fVaultCheck = & fdesetup status 2>&1 if ($LASTEXITCODE -ne 0) { Write-Log "FileVault command not available" -Level "ERROR" return $false }
# Check admin privileges if (-not (Test-AdminPrivileges)) { Write-Log "Administrator privileges required" -Level "ERROR" return $false }
# Create backup directory if needed if (-not (Test-Path $KeyBackupLocation)) { New-Item -Path $KeyBackupLocation -ItemType Directory -Force | Out-Null Write-Log "Created backup directory: $KeyBackupLocation" }
return $true } catch { Write-Log "Prerequisites check failed: $($_.Exception.Message)" -Level "ERROR" return $false }}FileVault Status Check
Section titled โFileVault Status Checkโfunction Get-FileVaultStatus { try { $statusOutput = & fdesetup status $enabled = $statusOutput -match "FileVault is (On|Off)" $lastRotation = Get-LastRotationDate
return [PSCustomObject]@{ Enabled = ($statusOutput -match "FileVault is On") Status = $statusOutput LastRotation = $lastRotation RecoveryKeyPresent = Test-RecoveryKeyPresent } } catch { Write-Log "Failed to get FileVault status: $($_.Exception.Message)" -Level "ERROR" return $null }}Key Rotation Implementation
Section titled โKey Rotation Implementationโfunction Invoke-KeyRotation { param([bool]$TestMode)
try { Write-Log "Starting key rotation process"
if ($TestMode) { Write-Log "Running in test mode - no actual rotation will occur" return [PSCustomObject]@{ Success = $true NewKey = "TEST-KEY-$(Get-Random -Maximum 9999)" RotationDate = Get-Date TestMode = $true } }
# Generate new recovery key $newKey = & fdesetup changerecoverykey -personal 2>&1 if ($LASTEXITCODE -ne 0) { throw "Failed to generate new recovery key: $newKey" }
# Extract key from output $keyPattern = 'Recovery key: ([A-Z0-9\-]+)' if ($newKey -match $keyPattern) { $extractedKey = $matches[1] } else { throw "Could not extract recovery key from output" }
# Update last rotation date Set-LastRotationDate -Date (Get-Date)
Write-Log "Successfully generated new recovery key"
return [PSCustomObject]@{ Success = $true NewKey = $extractedKey RotationDate = Get-Date TestMode = $false }
} catch { Write-Log "Key rotation failed: $($_.Exception.Message)" -Level "ERROR" return [PSCustomObject]@{ Success = $false ErrorMessage = $_.Exception.Message RotationDate = $null } }}Key Backup Function
Section titled โKey Backup Functionโfunction Backup-RecoveryKey { param( [string]$Key, [string]$BackupPath )
try { $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $hostname = & hostname $filename = "filevault-key-$hostname-$timestamp.txt" $fullPath = Join-Path $BackupPath $filename
# Create backup file with metadata $backupContent = @"FileVault Recovery Key Backup==============================Generated: $(Get-Date)Hostname: $hostnameKey: $KeyScript Version: $ScriptVersionCompany: $CompanyName
IMPORTANT: Store this key in a secure location.This key can unlock the encrypted disk if the user forgets their password."@
# Write backup file Set-Content -Path $fullPath -Value $backupContent -Encoding UTF8
# Set secure permissions & chmod 600 $fullPath
# Encrypt backup file if possible if (Test-CommandAvailable "gpg") { try { & gpg --symmetric --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 --s2k-digest-algo SHA512 --s2k-count 65536 --passphrase-file "/etc/filevault-passphrase" --output "$fullPath.gpg" $fullPath if ($LASTEXITCODE -eq 0) { Remove-Item $fullPath -Force $fullPath = "$fullPath.gpg" Write-Log "Recovery key backup encrypted with GPG" } } catch { Write-Log "GPG encryption failed, keeping plaintext backup" -Level "WARNING" } }
Write-Log "Recovery key backed up to: $fullPath"
return [PSCustomObject]@{ Success = $true BackupPath = $fullPath Timestamp = $timestamp }
} catch { Write-Log "Failed to backup recovery key: $($_.Exception.Message)" -Level "ERROR" return [PSCustomObject]@{ Success = $false ErrorMessage = $_.Exception.Message } }}Cleanup Old Keys
Section titled โCleanup Old Keysโfunction Remove-OldKeys { param( [int]$RetentionDays, [string]$BackupPath )
try { $cutoffDate = (Get-Date).AddDays(-$RetentionDays) $keyFiles = Get-ChildItem -Path $BackupPath -Filter "filevault-key-*.txt*" -File
$removedCount = 0 foreach ($file in $keyFiles) { if ($file.CreationTime -lt $cutoffDate) { Write-Log "Removing old key file: $($file.Name)" Remove-Item $file.FullName -Force $removedCount++ } }
if ($removedCount -gt 0) { Write-Log "Removed $removedCount old key files older than $RetentionDays days" } else { Write-Log "No old key files to remove" }
} catch { Write-Log "Failed to remove old keys: $($_.Exception.Message)" -Level "ERROR" }}Utility Functions
Section titled โUtility FunctionsโLogging Function
Section titled โLogging Functionโfunction Write-Log { param( [string]$Message, [ValidateSet("INFO", "WARNING", "ERROR", "DEBUG")] [string]$Level = "INFO" )
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $hostname = & hostname $logEntry = "[$timestamp] [$hostname] [$Level] $Message"
# Write to log file Add-Content -Path $LogPath -Value $logEntry -Encoding UTF8
# Write to console if running interactively if (-not $env:USERPROFILE) { switch ($Level) { "ERROR" { Write-Host $logEntry -ForegroundColor Red } "WARNING" { Write-Host $logEntry -ForegroundColor Yellow } "DEBUG" { Write-Host $logEntry -ForegroundColor Gray } default { Write-Host $logEntry -ForegroundColor Green } } }}Admin Privileges Check
Section titled โAdmin Privileges Checkโfunction Test-AdminPrivileges { $currentUser = & id -u return $currentUser -eq 0}Command Availability Check
Section titled โCommand Availability Checkโfunction Test-CommandAvailable { param([string]$Command)
try { $null = & which $Command 2>&1 return $LASTEXITCODE -eq 0 } catch { return $false }}Date Management Functions
Section titled โDate Management Functionsโfunction Get-LastRotationDate { $stateFile = "/var/filevault-rotation-state.json"
if (Test-Path $stateFile) { try { $state = Get-Content $stateFile | ConvertFrom-Json return [DateTime]$state.LastRotation } catch { Write-Log "Failed to read rotation state file" -Level "WARNING" return (Get-Date).AddDays(-$RotationIntervalDays - 1) } } else { return (Get-Date).AddDays(-$RotationIntervalDays - 1) }}
function Set-LastRotationDate { param([DateTime]$Date)
$stateFile = "/var/filevault-rotation-state.json" $state = @{ LastRotation = $Date.ToString("yyyy-MM-ddTHH:mm:ssZ") ScriptVersion = $ScriptVersion Hostname = & hostname }
try { Set-Content -Path $stateFile -Value ($state | ConvertTo-Json -Depth 3) -Encoding UTF8 } catch { Write-Log "Failed to write rotation state file: $($_.Exception.Message)" -Level "WARNING" }}Deployment Instructions
Section titled โDeployment InstructionsโIntune Script Deployment
Section titled โIntune Script Deploymentโ-
Create Script Package:
- Save script as
FileVaultKeyRotation.ps1 - Create deployment package with configuration files
- Test script in development environment
- Save script as
-
Configure Intune Settings:
- Navigate to Microsoft Endpoint Manager
- Create new PowerShell script deployment
- Set script parameters for your environment
- Assign to appropriate device groups
-
Deployment Configuration:
{ "scriptSettings": { "fileName": "FileVaultKeyRotation.ps1", "runAsAccount": "system", "enforceSignatureCheck": false, "runAs32Bit": false }, "scheduleSettings": { "runOnce": false, "recurrence": "weekly", "startDateTime": "2024-01-01T02:00:00Z" }}Monitoring and Alerting
Section titled โMonitoring and Alertingโ# Create monitoring script for Intunefunction Monitor-FileVaultRotation { $logPath = "/var/log/filevault-rotation.log" $errorPattern = "ERROR"
$recentErrors = Select-String -Path $logPath -Pattern $errorPattern -Context 2 | Where-Object { $_.LineNumber -gt (Get-Content $logPath).Count - 100 }
if ($recentErrors.Count -gt 0) { # Send alert to IT team Send-Alert -Message "FileVault rotation errors detected" -Details $recentErrors }}Security Considerations
Section titled โSecurity ConsiderationsโKey Protection
Section titled โKey Protectionโ- Secure Storage: Store backup keys in encrypted location
- Access Control: Limit access to backup files
- Audit Trail: Log all key operations
- Retention Policy: Define key retention periods
Compliance Requirements
Section titled โCompliance Requirementsโ- Data Protection: Ensure compliance with data protection regulations
- Audit Logs: Maintain comprehensive audit trail
- Key Escrow: Implement secure key escrow process
- Documentation: Maintain security procedures documentation
Troubleshooting
Section titled โTroubleshootingโCommon Issues
Section titled โCommon Issuesโ- Permission Errors: Ensure script runs with appropriate privileges
- FileVault Status: Verify FileVault is properly enabled
- Backup Failures: Check storage space and permissions
- Network Issues: Ensure connectivity for centralized logging
Debug Mode
Section titled โDebug Modeโ# Enable debug logging$env:FILEVAULT_DEBUG = "true"Start-FileVaultKeyRotation -TestMode -VerboseRecovery Procedures
Section titled โRecovery Proceduresโ- Lost Keys: Use backup keys from secure storage
- Failed Rotation: Manual intervention may be required
- System Issues: Reboot and retry rotation process
Conclusion
Section titled โConclusionโThis FileVault key rotation script provides automated security enhancement for macOS devices in enterprise environments. By implementing regular key rotation with proper backup and audit procedures, organizations can maintain strong security posture while ensuring operational continuity.
The scriptโs modular design allows for customization based on specific organizational requirements while maintaining security best practices and compliance with regulatory requirements.
Regular monitoring and maintenance of the rotation process ensures continued effectiveness and helps identify potential issues before they impact security operations.