Storage providers
S3 Lens works with any storage that exposes an S3-compatible API. Add providers under the providers key in s3lens.yaml. See Configuration for the full field reference.
Supported backends
Section titled “Supported backends”S3 Lens is tested locally against Garage and SeaweedFS. The following providers are supported through the generic S3 client or GCS-specific settings:
| Provider | Config type | Notes |
|---|---|---|
| AWS S3 | generic |
Standard regional endpoints |
| Google Cloud Storage | gcp |
HMAC keys via S3-compatible XML API |
| Hetzner Object Storage | generic |
S3-compatible endpoint |
| Garage | generic |
Self-hosted; path_style: true |
| SeaweedFS | generic |
Self-hosted; path_style: true |
| MinIO | generic |
Optional local testing target |
| Other S3-compatible | generic |
Custom endpoint and credentials |
Generic S3-compatible setup
Section titled “Generic S3-compatible setup”Most providers use the same shape:
providers: - name: "my-storage" type: generic endpoint: "https://s3.example.com" region: "us-east-1" path_style: true credentials: access_key_id: "${S3_ACCESS_KEY_ID}" secret_access_key: "${S3_SECRET_ACCESS_KEY}"AWS S3
Section titled “AWS S3”providers: - name: "aws-prod" endpoint: "https://s3.amazonaws.com" region: "eu-west-1" credentials: access_key_id: "${AWS_ACCESS_KEY_ID}" secret_access_key: "${AWS_SECRET_ACCESS_KEY}"Use the regional endpoint that matches your buckets. Virtual-hosted-style URLs (path_style: false or omitted) typically work with AWS; self-hosted providers usually need path_style: true.
See Provider credentials and permissions for the IAM actions your access key needs.
Garage
Section titled “Garage”Garage is a lightweight self-hosted object store. Example local setup:
providers: - name: "garage-local" endpoint: "http://127.0.0.1:3900" region: "garage" path_style: true credentials: access_key_id: "${GARAGE_ACCESS_KEY_ID}" secret_access_key: "${GARAGE_SECRET_ACCESS_KEY}"Create an access key and grant bucket permissions with the Garage CLI:
garage key create s3lensgarage bucket create my-bucketgarage bucket allow --read --write my-bucket --key s3lensThe repository’s docker-compose.yml includes a Garage profile for local testing (just compose-garage-up).
SeaweedFS
Section titled “SeaweedFS”SeaweedFS exposes an S3 API on port 8333 by default:
providers: - name: "seaweed-local" endpoint: "http://127.0.0.1:8333" region: "us-east-1" path_style: true credentials: access_key_id: "${SEAWEED_ACCESS_KEY_ID}" secret_access_key: "${SEAWEED_SECRET_ACCESS_KEY}"Use the S3 credentials configured in your SeaweedFS filer setup. The Compose profile in this repository provides a ready-made local instance.
providers: - name: "minio-local" endpoint: "http://127.0.0.1:9000" region: "us-east-1" path_style: true credentials: access_key_id: "${MINIO_ACCESS_KEY}" secret_access_key: "${MINIO_SECRET_KEY}"MinIO is optional for local compatibility testing. Start it with docker compose --profile minio up -d (console at http://localhost:9001).
Hetzner Object Storage
Section titled “Hetzner Object Storage”providers: - name: "hetzner" endpoint: "https://fsn1.your-objectstorage.com" region: "fsn1" path_style: true credentials: access_key_id: "${HETZNER_ACCESS_KEY}" secret_access_key: "${HETZNER_SECRET_KEY}"Use the endpoint and region from your Hetzner project dashboard.
Provider credentials and permissions
Section titled “Provider credentials and permissions”Each provider entry includes an access key and secret that S3 Lens uses on the server to call the storage API. These credentials are not shown to users in the UI or API responses.
S3 Lens has two separate permission layers:
- Provider credentials (this section) — what the storage backend allows the S3 Lens server to do
- Access policies — what each signed-in user is allowed to do in S3 Lens
Both must align. If a user has write access in S3 Lens but the provider key is read-only, uploads and deletes fail with errors from the storage backend.
Scope provider credentials to the buckets S3 Lens should manage. Prefer keys or IAM policies limited to those buckets rather than account-wide admin access.
Operations S3 Lens performs
Section titled “Operations S3 Lens performs”| Feature | S3 API call | Permission needed |
|---|---|---|
| List buckets | ListBuckets |
List all buckets in the account/project |
| Create bucket | CreateBucket |
Create buckets |
| Delete bucket | DeleteBucket |
Delete empty buckets |
| List objects / folders | ListObjectsV2 |
List objects in a bucket |
| Download / bulk ZIP | GetObject |
Read objects |
| Upload | PutObject |
Write objects |
| Copy | CopyObject |
Read source object; write destination object |
| Rename | CopyObject + DeleteObject |
Read, write, and delete objects |
| Delete / bulk delete | DeleteObject, DeleteObjects |
Delete objects |
| Presigned URL | Presigned GetObject |
Read objects (used to sign URLs) |
AWS S3 and Hetzner (IAM-style)
Section titled “AWS S3 and Hetzner (IAM-style)”On AWS and Hetzner Object Storage, map the table above to IAM Action values:
| Capability | IAM actions | Resource |
|---|---|---|
| Browse buckets and objects | s3:ListAllMyBuckets, s3:ListBucket, s3:GetObject, s3:GetBucketLocation |
* for list-buckets; bucket ARN for list; object ARN for get |
| Upload, copy, rename | s3:PutObject, s3:GetObject (source for copy/rename) |
arn:aws:s3:::bucket-name/* |
| Delete objects | s3:DeleteObject |
arn:aws:s3:::bucket-name/* |
| Create / delete buckets | s3:CreateBucket, s3:DeleteBucket |
bucket ARNs as needed |
Read-only example (single bucket):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"], "Resource": "*" }, { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::my-bucket" }, { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::my-bucket/*" } ]}Read/write example (single bucket, including copy, rename, and presigned URLs):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"], "Resource": "*" }, { "Effect": "Allow", "Action": ["s3:ListBucket", "s3:CreateBucket", "s3:DeleteBucket"], "Resource": "arn:aws:s3:::my-bucket" }, { "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::my-bucket/*" } ]}For multiple buckets, add one statement block per bucket or use wildcard bucket names if your provider supports them. Managed policies such as AmazonS3ReadOnlyAccess work for read-only browsing; for writes, prefer a custom policy scoped to specific buckets over AmazonS3FullAccess.
Temporary credentials (STS) are supported via credentials.session_token when your deployment supplies them.
Google Cloud Storage (IAM roles)
Section titled “Google Cloud Storage (IAM roles)”GCS HMAC keys inherit permissions from the service account or user they belong to. Grant IAM on the buckets or project:
| Capability | Example IAM role |
|---|---|
| Browse buckets and objects | roles/storage.objectViewer on the bucket or project |
| Upload, delete, copy, rename | roles/storage.objectAdmin on the bucket |
| Create and delete buckets | roles/storage.admin at project level, or bucket-level admin as appropriate |
For read-only access to specific buckets, bind roles/storage.legacyBucketReader and roles/storage.objectViewer on those buckets rather than granting project-wide admin.
Garage
Section titled “Garage”Garage uses per-key bucket ACLs. After creating a key, grant access on each bucket:
garage bucket allow --read my-bucket --key s3lens # browse and downloadgarage bucket allow --read --write my-bucket --key s3lens # upload, copy, rename, deleteTo create or delete buckets through S3 Lens, the key needs permission to manage buckets in your Garage layout (typically the same key with write access, plus bucket-admin rights in your Garage setup).
SeaweedFS and MinIO
Section titled “SeaweedFS and MinIO”These accept standard S3 access keys. Configure the key in your filer or MinIO policy with the same action set as the AWS table above — at minimum ListBucket, GetObject, PutObject, and DeleteObject on the buckets S3 Lens uses. MinIO policy documents use the same s3:* action names as AWS.
For local development, admin credentials from the Compose profiles are sufficient. In production, create a dedicated user or policy scoped to the required buckets.
Choosing a permission level
Section titled “Choosing a permission level”| Use case | Provider credentials |
|---|---|
| Read-only file browser | List + get only |
| Full object management (no bucket admin) | List + get + put + delete on target buckets |
| Bucket create/delete in the UI | Above plus create/delete bucket |
| Presigned URL sharing | Get on objects users may link to |
Match provider credentials to the most capable access policy you assign to any user. You can use a narrower provider key if all users are read-only, or a broader key if some users need write access — S3 Lens policies then restrict who can trigger each operation.
Google Cloud Storage (GCS)
Section titled “Google Cloud Storage (GCS)”S3 Lens connects to GCS through Google’s S3-compatible XML API using HMAC keys — not OAuth or service-account JSON files.
- In Cloud Console → Storage → Settings → Interoperability, create an HMAC key for a service account (preferred) or user account.
- Grant that principal IAM roles on the buckets you need — see Provider credentials and permissions for role guidance.
- Add a provider block:
providers: - name: "gcp-playground" type: gcp project_id: "${GCS_PROJECT_ID}" endpoint: "https://storage.googleapis.com" region: "auto" path_style: true credentials: access_key_id: "${GCS_ACCESS_KEY_ID}" secret_access_key: "${GCS_SECRET_ACCESS_KEY}"When type is gcp, S3 Lens defaults endpoint to https://storage.googleapis.com and path_style to true if omitted. project_id is required and is sent as x-amz-project-id on S3 XML API calls.
Recommended settings
Section titled “Recommended settings”| Setting | Value | Notes |
|---|---|---|
| Endpoint | https://storage.googleapis.com |
Global XML API endpoint |
| Region | auto |
Google’s S3 SDK guidance recommends auto; bucket location (e.g. europe-north2) also works |
| Path-style | true |
Avoids virtual-hosted certificate issues |
| Auth | HMAC access key + secret | Session tokens are not used for GCS HMAC |
Known limitations
Section titled “Known limitations”- HMAC only — OAuth and Application Default Credentials are not supported through this path
- Uniform bucket-level access — works normally; ACL headers on upload are ignored when uniform access is enabled
- Organization policy —
constraints/storage.restrictAuthTypescan block HMAC keys; contact your GCP admin if you see403 Forbidden - List page size — GCS returns at most 500 keys per list call via the S3 API; S3 Lens paginates automatically
- Bucket create/delete — may require location constraints and project permissions beyond object CRUD
- Unsupported S3 features — bucket policies, event notifications, and requester-pays differ from AWS (see Google’s migration docs)
Troubleshooting
Section titled “Troubleshooting”| Symptom | Things to check |
|---|---|
SignatureDoesNotMatch |
Verify credentials, region, and path_style; for GCS, confirm HMAC keys are active |
| Cannot list buckets | Confirm the access key has list permissions; check endpoint URL |
| SSL/certificate errors | Try path_style: true for self-hosted providers |
| Provider missing in UI | Check the provider name in config; verify credentials env vars are set |
| 403 on GCS | HMAC keys may be blocked by org policy; verify IAM roles on buckets |
After changing providers in s3lens.yaml, restart S3 Lens. Provider credentials are never returned by the API — use GET /api/providers to confirm a provider is configured without exposing secrets.
Multiple providers
Section titled “Multiple providers”You can connect several backends at once. Use access policies to control which users see which providers:
policy: policies: garage-readonly: allow: - actions: [read] resource: { provider: "garage-local", bucket: "*", prefix: "*" }Users with this policy can browse Garage but not other configured providers (unless additional policies grant access).