Skip to main content

<object-storage-proxy ⚡> Yet Another Object Storage Proxy

Project description

CI PyPI version PyPI downloads License: MIT Rust edition

<osp⚡> object-storage-proxy

A fast, in-process reverse proxy for AWS S3 and IBM Cloud Object Storage, built on Cloudflare's pingora. It exposes a Python interface so you can plug in your own credential fetching, request signing, and authorization logic without touching the Rust core.

Note: This project is under active development. APIs are likely to change before 1.0.

Why

Object storage backends like IBM COS assign one endpoint and one set of credentials per storage instance, which may contain many buckets. Managing credentials and endpoints across instances becomes cumbersome, especially when clients expect a single uniform endpoint.

This proxy solves that by:

  1. Translating path-style requests (http://proxy/bucket/key) to virtual-hosted-style (https://bucket.s3.region.host/key) on the way out.
  2. Re-signing requests with the correct backend credentials, so clients only need one keypair pointed at the proxy.
  3. Calling your Python functions for credential lookup and request authorization, with TTL-based caching.

Request lifecycle

Request stages

Features

  • Compatible with any AWS S3-compatible client: aws-cli, boto3, polars, spark, datafusion, presto, trino, ...
  • Decouples frontend authentication (what the client sends) from backend authentication (what the storage expects).
  • Python callables for credential fetching, HMAC key lookup, and per-request authorization.
  • TTL-based credential and authorization caching.
  • HTTP and HTTPS frontends (HTTPS supports HTTP/2).
  • Configurable thread count and per-URL request counting.
  • Presigned URL support with configurable max-usage limiting.
  • Built-in Prometheus metrics endpoint (/metrics) — on by default, opt-out via --no-default-features.

Installation

pip install object-storage-proxy

Or install from source (requires Rust stable and uv):

git clone https://github.com/opensourceworks-org/object-storage-proxy.git
cd object-storage-proxy
uv run maturin develop --release

See DEVELOP.md for full develop/build instructions including Nix and Taskfile usage.

Quick start

1. Configure your AWS client

~/.aws/config:

[profile osp]
region = eu-west-3
output = json
services = osp-services
s3 =
    addressing_style = path

[services osp-services]
s3 =
  endpoint_url = http://localhost:6190

~/.aws/credentials:

[osp]
aws_access_key_id = MYCLIENTID
aws_secret_access_key = myclientsecret

The aws_access_key_id is passed as the token argument to your Python callables. It can be any identifier meaningful to your auth system: an internal client ID, an OAuth2 subject, etc.

2. Write your server script

import json
import os
from object_storage_proxy import ProxyServerConfig, start_server

def fetch_credentials(token: str, bucket: str) -> str:
    # Return either an IBM COS API key string, or a JSON string:
    # '{"access_key": "...", "secret_key": "..."}'
    return json.dumps({
        "access_key": os.environ["BACKEND_ACCESS_KEY"],
        "secret_key": os.environ["BACKEND_SECRET_KEY"],
    })

def lookup_secret(access_key: str) -> str | None:
    # Called to verify incoming HMAC signatures.
    return os.getenv("MYCLIENTSECRET") if access_key == "MYCLIENTID" else None

def authorize(token: str, bucket: str, request: dict) -> bool:
    # Return True to allow, False to deny.
    return True

cos_map = {
    "my-bucket": {
        "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
        "region": "eu-de",
        "port": 443,
        "ttl": 300,
    },
}

config = ProxyServerConfig(
    cos_map=cos_map,
    bucket_creds_fetcher=fetch_credentials,
    hmac_fetcher=lookup_secret,
    validator=authorize,
    http_port=6190,
)

start_server(config)

3. Run it

uv run python my_server.py

4. Use it

aws s3 ls s3://my-bucket/ --profile osp
aws s3 cp file.txt s3://my-bucket/file.txt --profile osp

A fuller example with HTTPS, HMAC keystores, and IBM COS is in examples/minimal_server.py.

Configuration reference

ProxyServerConfig

Parameter Type Required Default Description
cos_map dict yes Bucket-to-backend mapping. See below.
hmac_keystore list[dict] no [] Static HMAC keypairs accepted on the frontend.
bucket_creds_fetcher callable(token, bucket) -> str no Called once per bucket to fetch backend credentials. Return an IBM COS API key string or {"access_key":...,"secret_key":...} JSON.
hmac_fetcher callable(access_key) -> str | None no Called per request to resolve a secret key from an access key, used to verify incoming signatures.
validator callable(token, bucket[, request]) -> bool no Called per request to authorize access. Cached by (token, bucket) for the bucket TTL.
http_port int one of http/https required HTTP listener port.
https_port int one of http/https required HTTPS listener port (HTTP/2 supported).
threads int no 1 Number of worker threads.
verify bool no None Disable TLS verification on upstream connections. Development only.
skip_signature_validation bool no False Skip verification of incoming request signatures. Development only.
max_presign_url_usage_attempts int no 3 Max times a presigned URL may be used before being rejected.
server_name str no "osp" Server name included in log output.
metrics_port int no None Port to expose the Prometheus /metrics scrape endpoint. When None no endpoint is started.

cos_map entries

Each key is the bucket name as the client addresses it. The value is a dict:

Field Required Description
host yes Backend hostname
port yes Backend port (typically 443)
region no AWS/COS region string
apikey no IBM COS IAM API key (mutually exclusive with access_key/secret_key)
access_key no Backend HMAC access key
secret_key no Backend HMAC secret key
ttl no Credential and auth cache TTL in seconds. Default 300. Set to 0 to disable.
addressing_style no "path" or "virtual" (default "virtual")
is_tls_enabled no Defaults to true when port is 443

Python callable signatures

# Fetch backend credentials for a bucket.
# token: the access key from the client's Authorization header.
# Return an IBM COS API key string, or JSON: '{"access_key":"...","secret_key":"..."}'
def fetch_credentials(token: str, bucket: str) -> str: ...

# Resolve the secret key for an access key (used to verify incoming signatures).
def lookup_secret(access_key: str) -> str | None: ...

# Authorize a request. request dict contains: method, path, query, headers.
def authorize(token: str, bucket: str, request: dict | None = None) -> bool: ...

Prometheus metrics

The proxy ships with a built-in Prometheus scrape endpoint. Set metrics_port to enable it:

config = ProxyServerConfig(
    cos_map=cos_map,
    http_port=6190,
    metrics_port=9090,   # exposes http://localhost:9090/metrics
)

Then scrape it:

curl http://localhost:9090/metrics

Or add a Prometheus scrape config:

scrape_configs:
  - job_name: object-storage-proxy
    static_configs:
      - targets: ["localhost:9090"]

Exposed metrics (all prefixed osp_):

Metric Type Labels Description
osp_requests_total Counter method, bucket, status Total proxied requests
osp_request_errors_total Counter method, bucket, error 4xx / 5xx responses
osp_transfer_bytes_total Counter direction (rx/tx), bucket Bytes transferred
osp_presigned_url_hits_total Counter bucket Presigned URL uses
osp_presigned_url_rejected_total Counter bucket Presigned URLs rejected (over limit)
osp_active_connections Gauge In-flight connections
osp_memory_bytes Gauge Resident set size (Linux only)
osp_build_info Gauge version, rustc Static build metadata
osp_request_duration_seconds Histogram method, bucket End-to-end request latency
osp_response_size_bytes Histogram method, bucket Response body size

To build without the metrics endpoint:

maturin develop --no-default-features

HTTPS setup

Generate a self-signed certificate for local development:

openssl req -x509 -nodes -days 365 \
  -newkey rsa:4096 \
  -keyout key.pem \
  -out cert.pem \
  -config localhost.cnf

export TLS_CERT_PATH=/path/to/cert.pem
export TLS_KEY_PATH=/path/to/key.pem

Then pass https_port=8443 to ProxyServerConfig.

Environment variables

See .env.example for the full list. Key variables:

Variable Description
COS_API_KEY IBM COS IAM API key
AWS_ACCESS_KEY / AWS_SECRET_KEY AWS backend credentials
TLS_CERT_PATH / TLS_KEY_PATH Paths to TLS certificate and key
OSP_ENABLE_REQUEST_COUNTING Set to true to enable per-URL request counting
AWS_REQUEST_CHECKSUM_CALCULATION Set to WHEN_REQUIRED to avoid checksum errors with AWS CLI v2

Build targets

Pre-built wheels are published to PyPI for the following platforms:

Platform Architecture Libc Python
Linux (ubuntu-22.04) x86_64 glibc (manylinux) 3.x
Linux (ubuntu-22.04) aarch64 glibc (manylinux) 3.x
Linux (alpine 3.18) x86_64 musl (musllinux_1_2) 3.x
macOS (macos-14) aarch64 (Apple Silicon) 3.x
Source distribution any any 3.x

Windows builds are not currently active in CI. An sdist is always published so you can build from source on any platform with Rust stable installed.

Building from source

See BUILD.md.

Roadmap

These backlog items are currently not yet implemented:

  • Pass path and method to Python callbacks; cache by (token, bucket, path, method)
  • Expose pingora server and service configuration directly to Python
  • Spark streaming write support
  • AWS CLI checksum workaround (aws/aws-cli#9214)
  • Allow same bucket name on different providers
  • Pluggable distributed cache

Contributing

See CONTRIBUTING.md. Bug reports and feature requests go through GitHub Issues.

License

MIT

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

object_storage_proxy-0.6.0.tar.gz (1.4 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.2 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.0 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.6.0-cp314-cp314-macosx_11_0_arm64.whl (6.7 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.2 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.0 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.6.0-cp313-cp313-macosx_11_0_arm64.whl (6.7 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.0 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.6.0-cp312-cp312-macosx_11_0_arm64.whl (6.7 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

object_storage_proxy-0.6.0-cp311-cp311-musllinux_1_2_x86_64.whl (7.4 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.2 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.0 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.6.0-cp311-cp311-macosx_11_0_arm64.whl (6.7 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.2 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64

File details

Details for the file object_storage_proxy-0.6.0.tar.gz.

File metadata

  • Download URL: object_storage_proxy-0.6.0.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.13.3

File hashes

Hashes for object_storage_proxy-0.6.0.tar.gz
Algorithm Hash digest
SHA256 02ba76228e648d964a2e79321357af025b5a84397c4e90722c0cba9556866178
MD5 5b272ac937d5f24c3927222f47417184
BLAKE2b-256 9d1de830cce4a624593f4a305c3883e7f0f7a10ebeffe278444cd6c5ac9fe13a

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e7e75c4ebec126b11ff4dff2779ae191e835fe159783fa93d6ccb5ba67a4c918
MD5 d593394f96006b2106ea003f4529bd39
BLAKE2b-256 d5bda29fde59c0f1fc081e0807c05d7cb8740f3281a642a33f0a9fb2a7ab798d

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2d352c7f3e87bac5cd745a453590bf25399a11838f7a20adf1713595597fe7b9
MD5 17eebf0d40585023b5e38056a8607ff5
BLAKE2b-256 f0662ab9c65ccc17eb8b91a56e5a5e5c3221d28232f18ae187da4aad339cce0d

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 423c2d86e2d94b8a85d242437f5042febf998ed902538d1ea9f1dbedb8f44759
MD5 283e711402387d85df2ac91701672401
BLAKE2b-256 a8d6af2207a70da9b13e99e4aeecb1949784faf333819c7d3cbef4f39bb9727c

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2215565df1b11f7a09f68f5db14f5260cf634355de9d068d86440d6553c8e63f
MD5 e3f2cd767ef2e2a87c829566ad851095
BLAKE2b-256 ffb882468a787edf918ab0be95811b66aa39afb9fb91aeb29b3be7da23274749

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 58304ff00508186318fd61ffbc59f9c29aecda34a4fe0095a4a9b78a70e555ea
MD5 28fabdb0b26c7cc1c71f10c8f198d7b4
BLAKE2b-256 5e256df86a8f90bc370bd6d9a1bf2a066b0ed8553a2df223dfa47cdf7d8f8ba9

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0cebc5a71ec83c6811eb1bb52b7a7b9de714e4d29a233fba4a3f95c4684c1c4d
MD5 31559b333b92364b6eb95d7437bd1a09
BLAKE2b-256 977a465e3c62765f7fe9ce224d180971e319d6b404c04082009c8382ea95cf12

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 88fb87ff7c07d7d178e58b18c6303c1908852183cd4be83afb410e7db9adfecd
MD5 1da0d6059f3bf93ed27cbfd65721f251
BLAKE2b-256 80b08bde08bceef62b154f8d2ab64e32cc1673056b5ee3ded32bf4de0ce7ca3d

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5b55890c04888f32911ed2b21d3fce70a850a8b3bff12364a26444a27003ac99
MD5 5c159375f580dae1166c6e86e4b0c651
BLAKE2b-256 95790c285249b796ff2b1c6ab6a6f3dfebb306f9454f98bf28f1e3524f0089a4

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e194620d4284fe07d09a45b92b7aa3955b37d65d5a10069afc421f72b90f3083
MD5 57538ad464ff1c29147fdc9e72cd3f79
BLAKE2b-256 4ebbc3935fce5a87f42c143cbd688ad7e8b072bc0954b60b613980677b3e5e20

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 7905d39914b460d330883459141ce47a579f7afb2b52c92c34cfe1d441d7da84
MD5 45bce0551f014e4a065b3f48e117bd10
BLAKE2b-256 9eee8418c04471eb9604fcfa75690bea8822f2286a35d23644fb31d77d06bdd0

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e882d4540bd42a2b008093a9fe7fd73e7425e0f2ea417712854ab828ad76cc0c
MD5 615a9523a3153553ad7ffbe55bede2ac
BLAKE2b-256 3a5ff95b94fd7401e1d640c550c9c74a702e3cda1ff934607ab8b66eeabc032b

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ea89dccf9da2444af74f6bd61e09784aa352550a45aeab33e78fa8b40ba9042b
MD5 aaca4b2b658a4f57b12651058ff492da
BLAKE2b-256 d5f6ad860756afef0f483128e19ec2b7741a7004990e6a34eab6ef16fcafcab4

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 60ac36bdf04ad6f073bf378dd10931afb981e727aee709ba19ab215952d0d340
MD5 8c15a529eb546c790d0ad4187b1b2419
BLAKE2b-256 0c539c4838d749a0cb817f754a431ce36f2f5d65acec8ca4c0ba98858d8eaa59

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 723a36c5beddacbab05946b6865661f3e93bb808edfec8d19fb2f17625e481dd
MD5 28d6beb5d4e7e0b2e9dbfdbd24803cd6
BLAKE2b-256 05762607792ae44d8fa580f93a3c17c0b875d6e6315b96f8e7282e6748641985

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 72cac60aaca9bfadc3d3200d2ef6c393bf2a3a0b3a39b4b7e8f18b28fd80a4f8
MD5 d53199dc0ca123e68073a8c87434a60f
BLAKE2b-256 0c69ac518976ddfb8b023c8eb004cc50b50f32f68e99cba3438b8ee3c35120c6

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c74a77af5c1066751558dd63f23cd160e7bacf8c64a346cde097a197e4b8dca
MD5 411d814d5c8a21b8a7267a190587e357
BLAKE2b-256 d11eba2628cabc092984610d2b8c6c5119be87fdd6da986ae1ba52d791b8d316

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a5cd3c64de211beb43121e51f1de5999cb72e9f1e4d8f8a68d83f318f83ef090
MD5 8e8175524912a8d12bc26865399046d0
BLAKE2b-256 a97df59e7caa3d97af44f5a2bea448e039a14c8eb46b06387959ea13807dce69

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page