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

  • Pass path and method to Python callbacks; cache by (token, bucket, path, method)
  • Expose pingora server and service configuration to Python
  • Spark streaming write support
  • AWS CLI checksum workaround (aws/aws-cli#9214)

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.5.5.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.5.5-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.5.5-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.5.5-cp314-cp314-macosx_11_0_arm64.whl (6.6 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

object_storage_proxy-0.5.5-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.5.5-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.5.5-cp313-cp313-macosx_11_0_arm64.whl (6.6 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

object_storage_proxy-0.5.5-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.5.5-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.5.5-cp312-cp312-macosx_11_0_arm64.whl (6.6 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

object_storage_proxy-0.5.5-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.5.5-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.5.5-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.5.5-cp311-cp311-macosx_11_0_arm64.whl (6.6 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

object_storage_proxy-0.5.5-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.5.5-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.5.5.tar.gz.

File metadata

  • Download URL: object_storage_proxy-0.5.5.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.5.5.tar.gz
Algorithm Hash digest
SHA256 34724f9e065cf748d50198cc624ffff29cd23bcaea593d076c2cae0c5817c218
MD5 89117de47820d14601ce81d2d95219b2
BLAKE2b-256 acf1c69b4a4305e85e78b81ae17dca4ef6a4d7f2e837074f2dfd94548130c164

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b8b02e51c0ffd3303f3d00aadc77f9e64eeb11f82ee64c74fbc34d272621931c
MD5 288b4e17c9a0d0a64aa638349ba886fc
BLAKE2b-256 1098b1e0cd679e5f74e612468efdbfeac812fb2de6e2f6c8412e78d0a6dad274

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 58297321d935f4b997bb2d9bf59f596ce4884c52b0ce5690976923cfe70cb43e
MD5 ec9674e4c1816f7dc8e36882420c72be
BLAKE2b-256 7608a94d79190c69ef93a777311ea2ecd946fd6b6562a1023660b1d39accf029

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 366d5218a86de5ae05b11d7304d1bda9a02c15654bedb457cdd7004c710e9c35
MD5 7d72cc31218c3f3f3e46bbe45a568c5a
BLAKE2b-256 55f8b0f29539ab25b5c5dd23afb0819e6e1e36dc3fde9a59d9e73398cbdf31bc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e70992dbb98b99f3322424bb0e824c7ec362d017782c6620c83f1e721a9cdc51
MD5 9b4f84fa0567dd6442ff61f40ee2a630
BLAKE2b-256 0f341501e359087a0106892655ef1a689d2035a27a4fdc91baa74d8873556c7a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a264a17e8b6040ed57a4cdf42e02ee87a1956caae9b4491c47ebf39f775ecf57
MD5 8d07ac17980b183e5373435817d514c8
BLAKE2b-256 92a50ec348d479ef8082e2678b1861821efbcdb42c8bc5be198363cc665d9232

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 55b0d61d7cd472524ec99e3491b01590ead4b9504891cdf77fcd1b83de8f3686
MD5 f02d582b72f89b1214a3fa108a159713
BLAKE2b-256 25c101f41d34f367e63fbb1741f3aaabfded400caf3f4f7f54fdd900e4c9acec

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4c8df71891c68a2e54c5552b2742470682121af5d511c6dabda39c376c87ee2a
MD5 f38e564b39e4a4b6c4e83f2179357185
BLAKE2b-256 b4876ff92238495379315ab3d75f63d90a82fa85e9038c0df0437259d603ef5c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c2d790051026c2f26c9265e74b8df233ecaa4dc6cbfb832983e6ca380672de61
MD5 00a95485e7326639cdf6ac9df8a55145
BLAKE2b-256 e7aa30a05370668856c78af17b29bc01f36b85b3cb920a87e45d7ed744960bbc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3faf993f5ae054bb2887d98135758a51a70088b3fc729f9a5f3c677e201f7a17
MD5 d0d69de8f33f3d1d787478f4a2010814
BLAKE2b-256 3a8ea95648b8a644d75fa10e5b4e2df429721211f2f32bee9cb6a6d514add71b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a805a7d30ee29bcabbefdb874c77f148de458fb8495af1087f88d34e23cab329
MD5 fbf472bf7e2f28eaad84ef0040bb5dde
BLAKE2b-256 981c000176c9321f0a2a0c5a2e6722477ed18d2819ae16b83db35998bb978018

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 021ca576162718e71311da520e33d335954a2654e2c9613528b2e800f23593ea
MD5 b50e33e3d21d445d32b71b39eb4a3aba
BLAKE2b-256 570ee3d61973cbd48d37d7ba5d9ac0528c6dedcd5cb3d8178cbd714727a8ae62

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 78c0aa3eb1efd137e968710aad36c2b6d0dae9059697f9d8928ed20d59897566
MD5 d33126444ad20f79f3214d707d0e0c86
BLAKE2b-256 8c5602bffaead0ed41477e4b4367a0afee77df95567e4d42560d6b62ed1fa134

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 71fda1c2cc6abcb798c498f9b6986a4b827ab0709487925da8afa1ddcdcfa5cc
MD5 eb22794e4940b16eb2a74dbe541a7c32
BLAKE2b-256 956ec09cadf87ed82a98942522a5fcd8a8c50956555bae9dfee3f8ac0d777345

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3a64272da20d4d109c640053dad54024289d4f3c6b98068836a8e14884a45b57
MD5 9314db768e445d8d7975997d299e3973
BLAKE2b-256 da0836de545f22ff528c4ffd285a712e47e0e4fbbdb00ab68faa24da93d08ee3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8810c3def3e34a876a2d4e857cb6d0d979f115ef5d92f81807a6aadaf7cda4c1
MD5 2a6e3e986abcdb997ed8b1f8d20e82d1
BLAKE2b-256 08815eee2025b316c370908cbed391f2ff18ab108131387fe75b2c30c0ea4eea

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ed68ce930a817042016bf05c8d43fdf49bfdfd706d331e7c2d844b3575d16e68
MD5 3d79a683368f77aa559c349cfe7761c9
BLAKE2b-256 a4e0ea2e2e3afc00d9b84aa12eaee37fdabc24ba28165cb0215aeff398dacbb5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6983a980276d2e8ee17d6f1a157029faec32f83c52a102cbce3c08dbb168f625
MD5 8d5fadefd1024c88bade0dbcbe3c9bee
BLAKE2b-256 8f5b8d3108356a9b8b3975b9881f076135866f8d9c48fa1c1eb0d0957b8f342b

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