Skip to content

Bring your own S3

By default Amendable stores Git layer tarballs in platform S3. Pro and Platform can point those objects at a bucket you own.

oidc.amendable.io mints a token, assumes your IAM role, writes to your us-west-2 bucket under a prefix.
ProviderAuthRegion / endpoint
Amazon S3 (S3)OIDCLocked to us-west-2. Client region and endpoints are ignored
Cloudflare R2 (R2)STATIC_KEYSYou set region, endpoint_url, access key, secret
MinIO (MINIO) or OTHERSTATIC_KEYSSame as R2. Private/link-local endpoints are rejected

UI: Settings → Bring-your-own storage

API (needs API_STORAGE):

Terminal window
curl -sS https://api.amendable.io/v1/storage-buckets/oidc-setup \
-H "access-token: $AMENDABLE_TOKEN"

Fields you must use as-is:

FieldExample
issuerhttps://oidc.amendable.io
audienceamendable-byo-storage
subjectaccount:<your-user-uuid>
regionus-west-2
sample_trust_policyIAM trust JSON with the correct hostname

The issuer hostname must match the environment you registered the bucket with. Always copy from this payload. Staging uses https://stage.oidc.amendable.io. See Environments.

subject is account: plus your user UUID, not your username.

  • Region us-west-2
  • Block public access
  • SSE-S3 is enough
  • Prefix, default amendable/
  • Do not use names that look like platform buckets (amendable-repos-*, amendable-download-*)

The module in examples/terraform/byo-s3 creates:

  • the bucket
  • the OIDC provider for oidc.amendable.io
  • a role whose trust policy matches aud and sub
  • S3 permissions on {prefix}* (canary + layers + multipart)
Terminal window
cd examples/terraform/byo-s3
terraform init
terraform apply \
-var aws_account_id=123456789012 \
-var bucket_name=my-amendable-layers \
-var amendable_user_id=YOUR_USER_UUID

The thumbprint in that example is the one used against the current issuer chain. If AWS starts rejecting it, refresh from the issuer TLS chain (SHA-1 of the top intermediate CA).

Minimum object actions: s3:GetObject, s3:PutObject, s3:DeleteObject, s3:AbortMultipartUpload, s3:ListMultipartUploadParts.

Verify writes {prefix}.amendable-canary/{uuid}.txt (Put, Head, Delete) then uses {prefix}layers/{layer-id}.tar.gz for Git.

Terminal window
curl -sS -X POST https://api.amendable.io/v1/storage-buckets \
-H "access-token: $AMENDABLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-layers",
"provider": "S3",
"auth_mode": "OIDC",
"bucket_name": "my-amendable-layers",
"key_prefix": "amendable/",
"role_arn": "arn:aws:iam::123456789012:role/amendable-byo-storage",
"is_default": true
}'

Status starts as PENDING_VERIFICATION. Then:

Terminal window
curl -sS -X POST \
https://api.amendable.io/v1/storage-buckets/BUCKET_ID/verify \
-H "access-token: $AMENDABLE_TOKEN"

Success: status is ACTIVE and last_validated_at is set. Failure: FAILED, flash or 422, and a row in Error log / GET /v1/storage-buckets/errors.

Pass storage_bucket_id on create, or set the bucket as account default. Binding cannot change later. You cannot delete a bucket that still has repos.

Terminal window
curl -sS -X POST https://api.amendable.io/v1/storage-buckets \
-H "access-token: $AMENDABLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "r2-layers",
"provider": "R2",
"auth_mode": "STATIC_KEYS",
"region": "auto",
"bucket_name": "my-r2-bucket",
"endpoint_url": "https://ACCOUNT_ID.r2.cloudflarestorage.com",
"key_prefix": "amendable/",
"access_key_id": "YOUR_ACCESS_KEY",
"secret_access_key": "YOUR_SECRET",
"is_default": true
}'

Then verify the same way. Secrets are envelope-encrypted at rest. They are never returned after create.

Verify checks assume-role (OIDC) and canary Put/Head/Delete. It does not prove:

  • that layers/*.tar.gz objects still exist
  • that GetObject on layers/ is still allowed

If you delete or overwrite layer objects, Git on a cold node can 500 (LoadImageError, S3 404, or digest mismatch). A warm node may still clone from cache. The BYO error log may stay empty. Treat layer keys as Amendable data. Do not tidy them.

After IAM changes, click Verify again. That is the check that writes a readable error.

GET /v1/storage-buckets/errors and Settings → BYO storage → Error log.

Operations you will see: ASSUME_ROLE, VALIDATE, UPLOAD, and similar. Retention: 30 days / 500 rows per user.

Common Verify failures:

SymptomCause
AccessDenied on assume-roleTrust iss host, aud, or sub mismatch; bad role ARN
S3 AccessDenied on canaryMissing Put/Head/Delete on {prefix}*
422 OIDC requiredAmazon S3 + static keys
422 bucket name invalidPlatform bucket name
403BYO requires Pro (feature flag)