Configure storage for encrypted Reinstate sessions
Reinstate v0.1.0-rc.8 stores encrypted manifests and immutable session
snapshots in a private S3-compatible bucket you control. Configure the service
endpoint, region, bucket, and profile prefix separately; interactive
rein init stores the access-key pair in the operating-system keyring, not in
config.toml.
Current scope: Cloudflare R2 is the recommended Phase 1 backend, and Amazon S3 is documented. Other S3-compatible services must implement the conditional request and object operations Reinstate uses; compatibility is not implied by an “S3-compatible” label alone.
Prerequisites
- A private bucket in an S3-compatible object-storage service.
- A service endpoint and region appropriate for that bucket.
- A dedicated, non-root credential limited to the intended bucket and profile prefix.
- Permission to list the prefix and get, put, head, and delete its objects.
- A retention, versioning, and incident-deletion policy you understand.
- Reinstate installed on a trusted local device.
Keep public website hosting and anonymous object access disabled. Reinstate does not require a Reinstate-hosted account or bucket.
Storage configuration fields
rein init writes non-secret storage coordinates similar to:
[storage]
type = "s3"
endpoint = "https://<service-endpoint>"
region = "auto"
bucket = "reinstate"
prefix = "profiles/<opaque-profile-id>"
credential_ref = "reinstate/<profile-id>/s3"
Use region = "auto" for R2. Use the bucket’s actual AWS Region and matching
regional endpoint for Amazon S3. The endpoint is the service URL only; do not
append the bucket name. bucket and prefix are independent fields.
The default prefix is profiles/<profile_id>. Every device in a profile must
use the same profile ID, bucket, and prefix. Credentials can differ by device
as long as each credential authorizes the same required object operations.
Required object operations
| Reinstate behavior | S3 operation or permission |
|---|---|
| List the profile tree | ListObjectsV2 / s3:ListBucket scoped by prefix |
| Read a manifest or snapshot | GetObject, HeadObject / s3:GetObject |
| Create a probe, snapshot, or manifest | PutObject / s3:PutObject |
| Remove the initialization probe | DeleteObject / s3:DeleteObject |
| Protect manifest updates | Conditional If-Match and If-None-Match writes |
Grant only the intended bucket and profiles/<profile_id>/ object prefix.
Provider-side deny policies, object retention, or Object Lock can prevent probe
cleanup or later operations even when an allow policy looks correct.
Remote object layout
The current backend uses:
<prefix>/manifest.age
<prefix>/snapshots/<opaque-snapshot-id>.age
<prefix>/probes/<random-id>
manifest.age is an encrypted index of session heads and profile revision.
Snapshots are immutable, UUID-addressed encrypted artifacts. Probe objects
contain a small test value and are deleted during successful initialization.
The provider can observe bucket access, object timestamps, sizes, fixed layout segments, and opaque IDs. It should not receive plaintext transcripts, manifest JSON, or the encryption passphrase.
Initialize and verify storage
Interactive setup is the preferred path:
rein init \
--project github.com/acme/app=/absolute/local/path
Enter the endpoint, bucket, access-key ID, and secret key in the private prompts. Initialization creates and deletes a probe before writing local configuration. On an additional device, pass the first device’s profile UUID:
rein init \
--profile-id DEVICE_A_PROFILE_UUID \
--project github.com/acme/app=/this/device/path
RC8 requires that additional-device initialization can find the existing
encrypted manifest.age; it does not silently create a new empty remote
profile.
After initialization:
rein doctor --self-test
rein status --json
rein push --agent AGENT --session SESSION_ID --dry-run --json
The doctor self-test uses synthetic data. The scoped dry-run authenticates and validates the real profile without publishing a snapshot.
Retention, backup, and deletion
Phase 1 has no Reinstate retention or garbage-collection command. Full
snapshots remain until removed by an explicit provider-side policy or operator
action. Deleting a snapshot referenced by the encrypted manifest can make that
session unrestorable; deleting manifest.age breaks an established profile.
Treat provider lifecycle rules, versioning, replication, Object Lock, and backup as external controls. Review how they interact with required probe deletion and with incident-response deletion before relying on them. Reinstate’s local pre-restore backups are separate plaintext files on the destination and are not a substitute for a remote storage recovery plan.
Expected evidence
initcompletes both probe creation and cleanup before saving config.config.tomlcontains only storage coordinates and acredential_ref, not an access key or secret key.- A first successful push creates encrypted
manifest.ageand one opaque.agesnapshot under the configured prefix. - An additional device verifies the existing manifest and
statusreports the same remote revision. - Inspecting stored bytes does not reveal plaintext transcript or manifest JSON.
Failure paths
- Use remote-manifest troubleshooting when an established profile appears empty or missing.
- A probe put failure usually means endpoint, region, bucket, credential, or
PutObjectscope is wrong; a cleanup failure can indicate missingDeleteObjector retention policy. - A signature mismatch often indicates the wrong regional endpoint, region, credential pair, or system clock; preserve redacted output.
- Do not bypass a missing manifest by uploading an empty file or changing the profile ID.
Security boundaries
Remote payloads are encrypted locally with age passphrase encryption before upload and transferred over TLS. The passphrase is never sent to the storage provider or stored by Reinstate. Interactive storage credentials are stored in the native OS keyring; non-interactive environment credentials are not persisted by Reinstate but remain exposed to the invoking process environment.
Encryption does not hide access timing, object size, bucket identity, endpoint, or every key segment. It also does not protect a compromised local machine or a secret already embedded in transcript text. Apply least privilege, provider-side access logging, credential rotation, and an independent backup policy.