ops: add encrypted off-host PostgreSQL backups
This commit was merged in pull request #2.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ScriptPath = '\\nas\MST\codex\assistent\deploy\windows\Sync-PostgresBackupToNas.ps1',
|
||||
[string]$KeyRecordPath = "$env:LOCALAPPDATA\Domovoy\postgres-backup-key.dpapi.json",
|
||||
[string]$NasKeyBackupPath = '\\nas\MST\codex\_backups\domovoy\keys\postgres-backup-key.dpapi.json',
|
||||
[string]$TaskName = 'Domovoy PostgreSQL Off-host Backup'
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$keyDirectory = Split-Path -Parent $KeyRecordPath
|
||||
New-Item -ItemType Directory -Force -Path $keyDirectory | Out-Null
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||
|
||||
if (-not (Test-Path -LiteralPath $KeyRecordPath) -and (Test-Path -LiteralPath $NasKeyBackupPath -PathType Leaf)) {
|
||||
Copy-Item -LiteralPath $NasKeyBackupPath -Destination $KeyRecordPath
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $KeyRecordPath)) {
|
||||
$random = [byte[]]::new(48)
|
||||
[Security.Cryptography.RandomNumberGenerator]::Fill($random)
|
||||
$plain = [Convert]::ToBase64String($random)
|
||||
try {
|
||||
$protected = ConvertFrom-SecureString (ConvertTo-SecureString $plain -AsPlainText -Force)
|
||||
$record = [ordered]@{ version = 1; project = 'domovoy'; purpose = 'postgres off-host backup'; protected_value = $protected; created_at_utc = [DateTime]::UtcNow.ToString('o') }
|
||||
[IO.File]::WriteAllText($KeyRecordPath, ($record | ConvertTo-Json) + "`n", [Text.UTF8Encoding]::new($false))
|
||||
}
|
||||
finally {
|
||||
[Array]::Clear($random, 0, $random.Length)
|
||||
$plain = $null
|
||||
}
|
||||
}
|
||||
& icacls.exe $KeyRecordPath /inheritance:r /grant:r "${identity}:F" | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw 'DPAPI key ACL hardening failed' }
|
||||
|
||||
$nasKeyDirectory = Split-Path -Parent $NasKeyBackupPath
|
||||
New-Item -ItemType Directory -Force -Path $nasKeyDirectory | Out-Null
|
||||
$nasKeyPartial = "$NasKeyBackupPath.$PID.partial"
|
||||
Copy-Item -LiteralPath $KeyRecordPath -Destination $nasKeyPartial
|
||||
Move-Item -LiteralPath $nasKeyPartial -Destination $NasKeyBackupPath -Force
|
||||
|
||||
if (-not (Test-Path -LiteralPath $ScriptPath -PathType Leaf)) { throw "Scheduled sync script not found" }
|
||||
$pwsh = (Get-Command pwsh.exe -ErrorAction Stop).Source
|
||||
$arguments = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$ScriptPath`""
|
||||
$action = New-ScheduledTaskAction -Execute $pwsh -Argument $arguments
|
||||
$daily = New-ScheduledTaskTrigger -Daily -At '04:00'
|
||||
$logon = New-ScheduledTaskTrigger -AtLogOn -User $identity
|
||||
$principal = New-ScheduledTaskPrincipal -UserId $identity -LogonType Interactive -RunLevel Limited
|
||||
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Hours 2)
|
||||
Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger @($daily, $logon) -Principal $principal -Settings $settings -Description 'Encrypt and replicate the latest Domovoy PostgreSQL backup to the private NAS.' -Force | Out-Null
|
||||
Write-Output "Scheduled task registered: $TaskName"
|
||||
Reference in New Issue
Block a user