Skip to content

ADR-0004: Use AWS S3 with Object Lock for Immutable Backup Storage

Date: 2026-06-26
Status: Accepted
Decision makers: PT


Context

Our existing backup setup consisted of:

  • SQLBak uploading daily backups to a Hetzner Storage Box
  • Synology NAS pulling a copy each morning as an on-premise redundancy layer

This setup remains in place and covers accidental deletion and hardware failure, but left two gaps:

  1. No immutability — a ransomware attack or compromised credentials could delete or overwrite backups on both the Storage Box and NAS.
  2. No tiered retention — all backups had a flat 30-day retention with no long-term archive layer for detecting slow-moving ransomware infections.

We considered:

  • Hetzner Storage Box alone — cheap and fast, but mutable; no protection against ransomware
  • Backblaze B2 with Object Lock — similar pricing, but less mature ecosystem and tooling
  • Azure Blob Storage with immutability — viable, but no existing Azure footprint
  • AWS S3 with Object Lock — well-documented, strong GDPR compliance, native Lambda integration for automation, competitive pricing

Decision

We add AWS S3 with Object Lock in Compliance mode as an immutable backup layer alongside the existing Hetzner Storage Box and Synology NAS. S3 is hosted in eu-north-1 (Stockholm) to keep data within the EU.

Backups are uploaded daily by SQLBak. An AWS Lambda function (backup-retention-manager) automatically copies files to tiered folders with extended retention:

Tier Folder Retention
Daily db/daily/<brand>/ 30 days
Weekly db/weekly/<brand>/ 90 days
Monthly db/monthly/<brand>/ 180 days

The same structure applies to file backups under files/.

Object Lock in Compliance mode means no user — including root — can delete or overwrite a locked object before its retention date. S3 Lifecycle Policies handle automatic cleanup once retention has expired.

SQLBak is configured with --single-transaction (and --lock-tables disabled) to eliminate site downtime during database dumps.


Consequences

Positive:

  • Backups are protected against ransomware, credential compromise, and accidental deletion
  • Tiered retention provides a 6-month window to detect and recover from slow-moving attacks
  • Data stays within the EU (GDPR compliant)
  • Fully automated — no manual intervention required for weekly/monthly promotion
  • CloudWatch alarms and SQLBak email notifications provide two layers of monitoring

Negative / trade-offs:

  • Object Lock retention periods cannot be shortened after being set — configuration mistakes require waiting out the retention period
  • Object Lock must be enabled at bucket creation and cannot be added to existing buckets
  • Slightly higher operational complexity compared to a plain Storage Box (Lambda, IAM, CloudWatch)
  • S3 egress costs apply when restoring large backups

Mitigation:

  • Retention periods are set conservatively and tested before go-live
  • IAM permissions follow least-privilege — SQLBak user and Lambda role each have only the permissions they need
  • Restore procedure is documented in backups.md