Bring Your Own Storage

Attach your own S3 or R2 bucket to OmegaSafe Cloud for your Delta storage. Remove limits and gain full control over Delta files.

1. Recommendation
#

OmegaSafe strongly recommends attaching your own storage bucket rather than relying on internal OmegaSafe Cloud storage. Our limits are generous and should not become a problem for typical use. However, we advertise direct user control over Delta files as a matter of principle, and long-term security - in case if your usage outlives OmegaSafe for any reason. Cloudflare R2 is a good example of a provider that you can use: its free tier is generous and well beyond typical OmegaSafe needs. Using your own bucket removes OmegaSafe’s aggregate per-key upload-count and download-count limits, gives you full control over your data, and lets you apply your own retention and access policies. Every individual Delta upload still has the universal 10 MiB limit, which is still twice the size the biggest Delta possible with our CLI settings. This limit applies on BYOS only as an extra protection layer for you.

You can create and manage storage configurations through:

2. Provider Configuration
#

Both R2 and S3 providers share a common set of fields. Provider-specific rules apply on top of those shared rules.

Field Reference
#

  • name (string, required): Maximum 255 characters. Only letters, digits, ., _, and - are allowed.
  • provider (string, required): r2 or s3.
  • bucket_name (string, required): 3–63 characters, lowercase letters, numbers, hyphens, and periods only. Must start and end with a lowercase letter or number. Must not contain ... Must not be an IPv4 address string.
  • region (string, required): One of the supported AWS region codes, or auto for R2.
  • access_key_id (string, required): 16–128 characters, [A-Za-z0-9+/=] only.
  • secret_access_key (string, required): 32–128 characters, [A-Za-z0-9+/=] only.
  • endpoint_url (string, optional): Must start with https:// when provided. Required for R2. Must be omitted or empty for S3.
  • remote_path (string, optional): Maximum 1024 characters. Must be relative, must not contain .., must not start with /, and must not contain <, >, :, ", |, ?, or *.

R2-Specific Rules
#

  • endpoint_url is required and must use the R2 account endpoint format, for example https://ACCOUNT-ID.r2.cloudflarestorage.com with no bucket name in the URL.
  • region must be "auto".

S3-Specific Rules
#

  • endpoint_url must be omitted or empty. Any non-empty value is rejected.
  • region must not be "auto". Use a valid AWS region code such as us-east-1.

Example: R2 Configuration
#

{
  "name": "production_r2",
  "provider": "r2",
  "bucket_name": "my-r2-bucket",
  "region": "auto",
  "access_key_id": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "secret_access_key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
  "endpoint_url": "https://ACCOUNT-ID.r2.cloudflarestorage.com",
  "remote_path": "omega-safe/deltas"
}

Example: S3 Configuration
#

{
  "name": "production_s3",
  "provider": "s3",
  "bucket_name": "my-production-bucket",
  "region": "us-east-1",
  "access_key_id": "AKIAIOSFODNN7EXAMPLE",
  "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "remote_path": "omega-safe/deltas"
}

3. Object Layout
#

OmegaSafe stores each Delta as a single object in your bucket. The effective object key depends on whether remote_path is set.

  • When remote_path is empty or null: the effective object key is {key_uuid}/{delta_uuid}.
  • When remote_path is set: the effective object key is {remote_path}/{key_uuid}/{delta_uuid}.

This is also the layout you must use when manually migrating Delta files from one storage to another before changing a key to a new storage_uuid.

Both key_uuid and delta_uuid must use the standard hyphenated UUID text form (8-4-4-4-12 hex characters), not a compact no-hyphen variant.

The directory segment named after key_uuid is always present in the object key. Each Delta object’s filename is exactly the delta_uuid string with no extension.

Empty path segments inside remote_path are removed when object keys are built. For example, a stored value of team//prod/ behaves like team/prod.

Examples:

  • Without remote_path: 234e5678-e89b-12d3-a456-426614174001/567e8901-e89b-12d3-a456-426614174004
  • With remote_path=customer-a/deltas: customer-a/deltas/234e5678-e89b-12d3-a456-426614174001/567e8901-e89b-12d3-a456-426614174004

Delta Upload Safeguards
#

Each Delta object must contain 1 to 10485760 bytes (10 MiB). Before upload, the client calculates the encrypted file’s MD5 digest locally and submits its exact size and Base64-encoded digest. The file moves directly from the client to S3 or R2; OmegaSafe does not receive the file body.

OmegaSafe signs Content-Length, Content-MD5, If-None-Match: *, and metadata containing the expected size, expected checksum, and a unique upload-attempt UUID. The storage service verifies Content-MD5 and rejects a different body, body size, or changed signed header.

Once a PUT succeeds, the same URL cannot overwrite that object and a repeated PUT returns 412 Precondition Failed. The client then asks OmegaSafe to confirm the upload using the upload-attempt UUID. OmegaSafe accepts the existing object only when its signed attempt metadata, size, and checksum metadata match. When a reliable single-part ETag is available, it must also match the expected MD5. An attempt mismatch returns a conflict and preserves the object; an integrity failure for the matching attempt triggers best-effort cleanup.

4. Connectivity Test
#

OmegaSafe runs a bucket connectivity test before saving a new storage configuration. When you edit an existing storage configuration, the test runs again only if you changed the connection details. Name-only edits do not trigger the test.

The test uses one fixed object named omegasafe_connection_test.json. This object is only a connectivity-check file. It is not a Delta object and it is not part of your normal stored key data.

The test object key is:

  • omegasafe_connection_test.json when remote_path is empty or null, which means the file is placed at the bucket root
  • {remote_path}/omegasafe_connection_test.json when remote_path is set, for example team/prod/omegasafe_connection_test.json

The uploaded test file is a JSON document with three fields:

  • storage_uuid
  • user_uuid
  • timestamp

The test runs in this order:

  1. LIST — verifies the credentials can list the relevant bucket path.
  2. PUT — uploads the JSON test file to the exact object key described above.
  3. GET — downloads that same object and compares the SHA-256 hash of the downloaded bytes against the hash of the uploaded bytes.
  4. DELETE (optional) — attempts to remove the test object.

If DELETE fails, the create or edit operation still succeeds because DELETE is optional for BYOS. The route logs a warning and communicates it back to the caller through an HTML flash message or a JSON warning field.

Because the test always uses the same fixed object key, a later connectivity test writes to that same location again. If an earlier test file is still present, the new PUT simply overwrites it before the GET verification step runs.

5. S3 IAM Policy
#

When using AWS S3, the IAM identity behind access_key_id and secret_access_key needs the following permissions:

  • s3:ListBucket on the bucket — required for create and edit connectivity checks.
  • s3:GetObject on bucket objects — required for connectivity verification, downloads, and object existence checks.
  • s3:PutObject on bucket objects — required for connectivity verification and presigned uploads.
  • s3:DeleteObject on bucket objects — optional. See Bring Your Own Storage — DELETE Permission Is Optional.

Minimal IAM Policy
#

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
    }
  ]
}

If you want OmegaSafe to also remove bucket objects during explicit Delta or key deletions, add s3:DeleteObject to the same object-level Action list that already contains s3:GetObject and s3:PutObject. For behavior when that permission is absent, see Bring Your Own Storage — DELETE Permission Is Optional.

6. R2 Permissions
#

When using Cloudflare R2, the credentials behind access_key_id and secret_access_key should allow the S3-compatible equivalent of:

  • Bucket LIST — required for create and edit connectivity checks.
  • Object GET — required for connectivity verification, downloads, and object existence checks.
  • Object PUT — required for connectivity verification and presigned uploads.
  • Object DELETE — optional. See Bring Your Own Storage — DELETE Permission Is Optional.

7. Browser CORS Configuration
#

Browser CORS configuration is needed only for browser-based delta transfers. OmegaSafe CLI and direct OmegaSafe API clients do not need browser CORS rules.

R2 CORS Example
#

[
  {
    "AllowedOrigins": ["https://app.omega-safe.com"],
    "AllowedMethods": ["PUT", "POST", "GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": [],
    "MaxAgeSeconds": 300
  }
]

S3 CORS Example
#

[
  {
    "AllowedOrigins": ["https://app.omega-safe.com"],
    "AllowedMethods": ["PUT", "GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": [],
    "MaxAgeSeconds": 300
  }
]

Note: If your bucket uses an explicit AllowedHeaders allowlist instead of ["*"], include Content-Type, Content-MD5, If-None-Match, x-amz-meta-expected-size-bytes, x-amz-meta-expected-content-md5, and x-amz-meta-upload-attempt to support browser Delta uploads.

8. Operational Consequences
#

Editing Storage Settings
#

Changing provider, bucket_name, region, endpoint_url, or remote_path takes effect immediately after the edit is committed. OmegaSafe does not move existing Delta objects between buckets or prefixes for you.

If you repoint a storage that is already attached to keys with existing Deltas, those files must already exist at the new effective object location or later download and delete flows will fail.

Before changing a key to a new storage, follow Keys Management — Object-layout requirement for manual Delta migration.

Note: OmegaSafe API — PATCH /keys/edit does not support moving a key back to internal storage.

Deleting a Storage Entry
#

OmegaSafe API — DELETE /storages/delete removes the storage record only. It does not enumerate or delete objects from the bucket. The route is blocked while any keys still reference that storage.

DELETE Permission Is Optional
#

This applies to both S3 and R2 BYOS credentials.

Normal successful Delta upload, confirm, download, and claim flows do not call DeleteObject. DELETE is attempted by the explicit OmegaSafe API — DELETE /deltas/delete and OmegaSafe API — POST /keys/delete (DELETE /keys/delete) routes. Confirmation also attempts cleanup when a matching upload attempt fails integrity validation. An upload-attempt mismatch preserves the object.

If the credentials lack delete permission, OmegaSafe still completes explicit record removal and instructs the caller to clean up remaining bucket objects manually. An integrity-invalid upload is rejected even when its cleanup attempt cannot delete the object. You can operate OmegaSafe without granting DELETE permission, but failed validation or explicit deletion can leave objects for manual cleanup.

Bucket Versioning Recommendation
#

OmegaSafe’s presigned Delta PUT uses If-None-Match: *, so normal upload URLs cannot overwrite an existing Delta object. Bucket credentials used directly outside OmegaSafe can still overwrite objects. Enabling bucket-side object versioning provides an additional recovery path for direct credential misuse, mistakes, or provider-side operational failures.

9. Internal Storage Limits
#

If you do not attach your own storage, a key uses OmegaSafe internal storage instead. The following per-key limits apply to internal storage:

  • Uploads: daily=2, monthly=5, stored=15
  • Downloads: daily=20, monthly=200

These aggregate limits are cost-safety controls, not a paid upgrade boundary. Keys using BYOS are not subject to them. The separate 10 MiB per-Delta upload limit and write-once presigned PUT safeguards apply to internal storage and BYOS.