Cloud backups
We connect to your source, with a credential you hand us for that purpose.
View as MarkdownA cloud backup runs on our infrastructure. You give us a credential for the source, we connect to it on the schedule, and we produce, encrypt and store the artifact.
The trade, stated plainly
There is no process for you to run. In exchange, we hold a credential to your data.
| Local | Cloud | |
|---|---|---|
| Who connects | Your worker | We do |
| Source credential | Your config.yaml | Our vault |
| Where plaintext exists | Your host | Our infrastructure |
| Where encryption happens | Your host | Our infrastructure |
| Runs while your machines are down | No | Yes |
| Reachability required | Worker to source | Our network to your source |
That last row is the one that decides most cases. A database on a private network with no public ingress cannot be a cloud backup, and should not be made into one by opening it.
If you are choosing between the two, choose local when you can run a worker and the source is sensitive, and cloud when the source is already reachable and you would rather not operate anything.
Where the credential lives
A cloud source's configuration is split the moment you save it, and the two halves land in different stores.
| Half | Stored in | Returned by the API | Examples |
|---|---|---|---|
| Public | Our database | Yes, as source | host, port, database, bucket, url, region |
| Secret | Vault | Never | password, access keys, request headers, TLS settings |
Two rules follow:
- The API writes secrets and never reads them back. No endpoint returns a secret it was given. Reading a backup shows you which database it connects to, not the password.
- A secret sent in the wrong half is still routed to Vault. The split is judged by the source type itself, not by which map you put a field in.
The dividing line is connection intent rather than sensitivity alone. TLS settings travel with the password because they describe the same connection and are worthless apart from it.
This is why an operator can audit which databases a workspace backs up without being handed the credentials to read them.
Configuring one
backups:
- name: prod-db
kind: cloud
source_type: postgres
schedule: "0 2 * * *"
source:
host: db.example.com
port: 5432
database: app
user: backup
credentials:
password: "<password>"
encryption:
public_key: ./keys/prod.asc
retention:
keep_last: 10
expire_after: 90dThe definition is validated when it is saved, not when it fires. A source that cannot run is refused at configure time rather than at 02:00 on a Sunday.
Credentials are plain values. apply runs on your machine against a file you control, so
keep that file out of the repository or render it at apply time. encryption.public_key is a
path, resolved relative to the manifest.
Source types
| Type | Fields |
|---|---|
postgres | host, port, database, user, schema, exclude_tables, no_owner, no_privileges, ssl_mode, password |
mysql | host, port, database, user, tables, exclude_tables, no_data, ssl_mode, password |
redis | host, port, db, user, tls, insecure, password |
s3 | bucket, prefix, region, endpoint, use_path_style, access_key_id, secret_access_key |
web | url, method, headers |
Every field of a source goes to the vault together, and none of it is returned by any endpoint. There is no half we keep back and show you: a hostname describes how to reach your database, so it travels with the password rather than being treated as harmless.
script, file and folder are never available as cloud backups. We do not execute
customer commands in our cloud, and your filesystem does not exist there. Submitting one is
refused, naming the type.
Reachability
Our side has to be able to open a connection to your source. In practice that means:
- A publicly resolvable hostname, or one reachable from our network.
- A firewall or security group that accepts the connection.
- TLS you are willing to terminate against a client that is not on your network.
Prefer a least-privileged role scoped to reading what the backup takes, and prefer TLS
with verification (ssl_mode: verify-full on Postgres) over trusting the transport.
Do not open a database to the internet to make a cloud backup possible. If the source is not already reachable, that is the signal to run a local backup instead.
Rotating a credential
Reconfigure the backup with the new secret. The next run uses it; runs already in flight finish on the old one.
sctl backup configure <backup-id> --credential password=<new-password>Revoking the old credential at the source is your step, and worth doing only after a run has succeeded on the new one.
Existing artifacts are unaffected: they are already encrypted and stored, and the source credential has nothing to do with reading them back.