Encryption and security
How Backup protects database credentials, destination credentials, and the backup archives themselves.
Backup handles three pieces of sensitive data: your database credentials, the credentials of BYO storage destinations, and the backup archives (your data, dumped). All are encrypted at rest; plaintext exists only in memory, inside short-lived scopes.
Credential storage (envelope encryption)
Database credentials and BYO destination credentials are protected the same way:
- A random 32-byte data encryption key (DEK) is generated via AWS KMS.
- The credentials are encrypted with AES-256-GCM using the DEK.
- The DEK itself is wrapped by a KMS key, bound to an encryption
context —
{organization, datasource}for database credentials,{organization, destination}for destination credentials. - Only the ciphertext, the wrapped DEK, and the key reference are stored. The plaintext and the DEK are wiped from memory immediately after sealing.
The encryption context matters: KMS refuses to unwrap a DEK unless the caller presents the exact same context, so ciphertext copied to a different organization or resource is undecryptable — a database leak alone yields nothing usable.
Credentials are write-only through the product: no dashboard screen or API response ever returns them.
How credentials reach the backup worker
When a job runs:
- The control plane assembles a one-job work order (job spec) containing the still-encrypted credential envelope and the destination details, and stores it encrypted, readable only via a short-lived presigned link.
- An isolated worker container is launched with just two inputs: the presigned link to its job spec and a callback URL for status reporting.
- The worker downloads the spec, calls KMS to unwrap the DEK (KMS
validates the encryption context), decrypts the connection string in
memory, and runs
pg_dump/mongodump.
Credentials live in worker memory for the duration of the job; the container is destroyed afterwards. Nothing persists between jobs.
Worker authentication (the webhook token)
The worker reports status back with a single-use opaque token minted for that one job: 48 random bytes, of which the control plane stores only a hash. Callbacks are verified with a constant-time hash comparison plus an HMAC signature over the payload, and the token's first use is recorded to prevent replay. A stolen token is useless for any other job — and can't read anything, only report status for its own.
Archive encryption
- In transit — the worker streams dump output to storage over HTTPS, always.
- At rest, managed storage — archives are stored with server-side encryption in Norcube's bucket.
- At rest, BYO destinations — per-destination setting:
sse-s3(the bucket's default encryption; R2, B2, Wasabi, and MinIO all encrypt at rest by default) orsse-kms(AWS S3 with a customer-managed KMS key). Set when creating the destination.
Connection security to your database
The worker connects to your database over the public internet from the
static egress IP 18.196.207.101 — see
Network access. TLS options in
your connection string (sslmode=require, tls=true) are honoured
end-to-end. The dump role should be
read-only.
Worker isolation
- Each backup runs in its own container — one job, one container, destroyed on exit. Nothing carries over between jobs.
- Containers run as a non-root user with minimal cloud permissions: fetch the job spec, unwrap the DEK, write to the one destination.
- Dump output streams straight to storage — no local disk, no temp files.
- Error reporting is classified: the raw
pg_dump/mongodumpstderr is reduced to a human-readable summary ("authentication failed", "disk full") before it's stored, so connection-string fragments can't leak into job records.
Auditability
Every sensitive operation writes an audit log entry — with deliberate redaction: credential saves record only a success flag; download-link generation records size and expiry but never the URL (the URL is the capability). Audit entries are kept for one year; the retention deletion trail (what was deleted, when, why, bytes freed) is kept permanently.