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.

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.

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: ...

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.3.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.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.5.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.5.3-cp314-cp314-macosx_11_0_arm64.whl (6.3 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

object_storage_proxy-0.5.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.5.3-cp313-cp313-macosx_11_0_arm64.whl (6.3 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

object_storage_proxy-0.5.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.5.3-cp312-cp312-macosx_11_0_arm64.whl (6.3 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

object_storage_proxy-0.5.3-cp311-cp311-musllinux_1_2_x86_64.whl (6.9 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

object_storage_proxy-0.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

object_storage_proxy-0.5.3-cp311-cp311-macosx_11_0_arm64.whl (6.3 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

object_storage_proxy-0.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64

File details

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

File metadata

  • Download URL: object_storage_proxy-0.5.3.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.3.tar.gz
Algorithm Hash digest
SHA256 9255fe98f9bc48881ad6ca5ad0080ec2ed8f8a409c9453aeea80a4c701d138e3
MD5 00a6eaa8a60abe36638a6b9bd29fbe55
BLAKE2b-256 ff211875d1fe5a551feb64225eab2e98f417e903f337e894addea3b9c9bdd167

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7b4f2406bc755fdcd1bda663b3260062161ccacb1ccaedc46e502d0d1fa515bf
MD5 c68372a370aa5b28aa51ede485f0ee64
BLAKE2b-256 14342f0c1986ab871fb56760be27aa5313cd2f046a22bdeb3122313b0982e4a9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 9e82f15e07fae31974935e17bb66abd0f39df83a79959b59e6987ccd2d1dc5b9
MD5 5e32ca1b9af106c5f7e5a8962cdee1ee
BLAKE2b-256 f20a3893c78c2212f5c03de6aacfb30bd8329f24efe9da760f0c74c71878eddc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b98fd3b3cf1eaf539b4e6b25fbae7852e2db9c61ba0be0d444a9891734d76cc7
MD5 37a77aca29b227c2a20cfcf48326015f
BLAKE2b-256 84d7a7369bebb0c263d36498bc62032f2c107bf8b75fcb2d84c73db1f73aacc2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5a84c3daceb2735bcf87c346d6dd529fced121d5c0e2d9d067faeb5ce5d1589d
MD5 8c65868586c9d34f1b10e7bf9445af5f
BLAKE2b-256 34417b6abbe245ecaab625e91d802b372cd9d0f1b48931e242211dd880ffa028

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 94f9ed248d5fab392d87d555e06e66da556a9b894b4c298b3fc3b05ecb20c4b0
MD5 71d4f885975793246a3801419aec0f7b
BLAKE2b-256 73c7742e203160b17dade131b5dee4be261e28f5217442bff78a9ed752d5e8cc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7a85bb4a43fbc1aa7b1113c22042e1969111c7d7531da3d0c7530b908a229007
MD5 436a455cb868522cc8f3550da002741e
BLAKE2b-256 874849f5a3fc1a19b4d4423f0f14eb056e8783a6610b6ec0727d16dbfbb950c5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b3b6dd8e68a89558dda17e6d8d6958dcb2d5858b0d44e2a8b468f5ee92d70913
MD5 6d75767f66a15368b9f3b4591657fa20
BLAKE2b-256 bd7ec926513b6136fdc370239773619823905d5dfaecd38b21a839f5bb88207f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bfeb2e788be11eed8bc616b1630fc3ab9ea9ada2eff327c9e27d03b12c9adef6
MD5 3bb93a08ffa9e7c7fdfe93844e5348ef
BLAKE2b-256 5b055947395310d85748adf479045b312631b7ae1dc62fc62daaf4dfa208189e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6022ab08f26a9dc0259301bc7960264cb3f287bf6c0ef01985bcad310e84a557
MD5 e274bc4deb2cea1b3db5a68fe765d83a
BLAKE2b-256 3839e2b2e6df34163d7049163ebc96662dcf6268af082189290219a0dfd0b603

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 01fe6b76d318488608936ebea8917462abdffc2117289c668a8ba1dc531aeb0f
MD5 6e899dcc262e4a3b384c85f486786d54
BLAKE2b-256 24a33e1e0bcb2261c25c6b338087ff9e19c68466780f65c0f3a4a82ab15f33ba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 de2a7dd3270e74bbfe5475f669dd661ba1d201f6b25f78d0817ba9c611e91811
MD5 4479502ca9f34b9f2ddef9305517e89d
BLAKE2b-256 bf1e7a1e2052ea0854c741c0ca60834be9c7d25be8c3a8ff00f6bdcdb1578325

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 19cb50d76d7f2cbd80d36af165a79a6339555f848247b98a09f50ec38e41dc0e
MD5 da825f20f0786c104f6d0f1c7453ae72
BLAKE2b-256 88ea233bc616fb12995f71c223c2dffe3d21d60d0fe913b47b36392e16289a74

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5d21222d4fc6fbd9113baa0ea5c7797493aaa1598a74c807966f0ad2ebfcb2cc
MD5 fcbe8e89890d1b3cf53e436efe06b43a
BLAKE2b-256 cc4ca91e40f79e30a141fb76e2e4095cbb85671b4eb22e61109861566dd2cb42

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 0dc2b91a99475716d2407b94ecabba0a779393c79eb2e1cad588865bc82b42df
MD5 aab82055030cac2d636d796e9a579490
BLAKE2b-256 809cb0de4d154d4b8d54c391b63537aed16d9c431b7da86cb227a73f16a3404a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c3f5cc27ab1d14585abba1ccc2607cd3e058a791d52b5a4abd86430b2e3a8e6d
MD5 b0df38cb080b399beef478e0272223d3
BLAKE2b-256 6cdf8befd9f5fa80acc64ff3b631be663305083fbf8228fa6a82cd24bbd5cf7c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 edb9d677effe688f10ab445d9c6d73ac26a788d2403821a0a3d77dd400ed7c8e
MD5 db16f7f353cba62f899a1d9ff5ca0095
BLAKE2b-256 6fe1243b817ba67cc90b500ff7fd6d5649d9119df46fd371b46d389fd282f1b7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 448e338d380d02a31340e270694007d511156c57ad2640d3f6991974dcf5533d
MD5 b796bf1344bc78181772ad9bd3236896
BLAKE2b-256 c9b3b515cfd094716fed1fbbed957d83dc1500dc596a07be691ad3e00bc2acdd

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