Skip to main content

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

Project description

CI PyPI - Downloads

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

📌 Note: This project is still under heavy development, and its APIs are subject to change.

Introduction

A fast and safe reverse proxy server, based on Cloudflare's pingora, to reverse proxy IBM Cloud Object Storage buckets.

  • Takes a Python authorization and api_key fetch callback function and cos bucket dictionary.
  • The validation is cached with optional ttl.
  • The apikey is used to authenticate against IBM's IAM endpoint and is cached and renewed on expiration.
  • If no apikey is provided, a Python function can be passed in to fetch the apikey for any given bucket.
  • HMAC support: passing in access and secret id keys, will be used to sign the request

The bucket dict contains for each bucket: - endpoint host - port - api key (optional) - ttl (optional, default 300) -> keep this reasonably short, but size to your needs

cos_map = {
    "bucket1": {
        "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
        "port": 443,
        "apikey": apikey,
        "ttl": 0
    },
    "bucket2": {
        "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
        "port": 443,
        "apikey": apikey
    },
    "proxy-bucket01": {
        "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
        "port": 443,
        "ttl": 300
    }
}

secrets

IBM COS Storage is built in a way where buckets are grouped by a cos (Cloud Object Storage) instance. Access to a bucket is managed by either an api key or hmac secrets, configured on the cos instance.

endpoint

Each bucket has its own endpoint: <bucket_name>.s3..cloud-object-storage.appdomain.cloud:.

The port is not always different, though, but it might be. Depends on your implementation.

You can imagine managing multiple buckets across instances can become quite cumbersome, even with aws profiles etc.

solution

There are two ways to access a bucket: through virtual addressing style (bucket.ibm-cos-host:port) and path style (ibm-cos-host/bucket).

your client (aws s3 compatible) -> http(s)://this-proxy/bucket01 -> https://bucket01.s3.eu-de.cloud-object-storage.appdomain.cloud:443

  1. translate path style to virtual style
  2. abstract authentication & authorization

Pass in a function which maps bucket to instance (credentials), and a function to map bucket to port (endpoint)

request lifecycle

authentication & authorization

The advantage is we can plug in a python authentication function and another function for authorization, allowing for fine-grained control.

authentication

We use the standard aws hmac header.

authorization

Pass in a callable from python which will be called from rust. This will be cached (ttl) for consequtive requests.

Examples

With local configuration.

~/.aws/config

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

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

~/.aws/credentials

[osp]
aws_access_key_id = MYLOCAL123
aws_secret_access_key = nothingmeaningful

Set up a minimal server implementation:

from object_storage_proxy import start_server, ProxyServerConfig
from dotenv import load_dotenv
import os
import random


load_dotenv()


def docreds(bucket) -> str:
    apikey = os.getenv("COS_API_KEY")
    if not apikey:
        raise ValueError("COS_API_KEY environment variable not set")
    
    print(f"Fetching credentials for {bucket}...")
    return apikey

def do_validation(token: str, bucket: str) -> bool:
    print(f"PYTHON: Validating headers: {token} for {bucket}...")
    # return random.choice([True, False])  # pointless now since cached
    return True


def main() -> None:
    apikey = os.getenv("COS_API_KEY")
    if not apikey:
        raise ValueError("COS_API_KEY environment variable not set")

    cos_map = {
        "bucket1": {
            "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
            "port": 443,
            "apikey": apikey,
            "ttl": 0
        },
        "bucket2": {
            "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
            "port": 443,
            "apikey": apikey
        },
        "proxy-bucket01": {
            "host": "s3.eu-de.cloud-object-storage.appdomain.cloud",
            "port": 443,
            "ttl": 300
        }
    }

    ra = ProxyServerConfig(
        bucket_creds_fetcher=docreds,
        validator=do_validation,
        cos_map=cos_map,
        port=6190
    )

    start_server(ra)


if __name__ == "__main__":
    main()

Run with aws-cli (but could be anything compatible with the aws s3 api like polars, spark, presto, ...):

$ aws s3 ls s3://proxy-bucket01/ --recursive --summarize --human-readable --profile osp
2025-04-17 17:45:30   33 Bytes README.md
2025-04-17 17:48:04   33 Bytes README2.md

Total Objects: 2
   Total Size: 66 Bytes
$

Server output:

$ uv run python test_server.py
2025-04-19T13:19:54.402023+02:00  INFO object_storage_proxy: Logger initialized; starting server on port 6190
2025-04-19T13:19:54.402361+02:00  INFO object_storage_proxy: Bucket creds fetcher provided: Py(0x100210680)
Fetching credentials for bucket01...
2025-04-19T13:19:54.402485+02:00  INFO object_storage_proxy: Callback returned: Kn2t...
[src/lib.rs:327:5] &run_args.cos_map = Py(
    0x000000010061aa00,
)
2025-04-19T13:19:54.403738+02:00  INFO pingora_core::server: Bootstrap starting
2025-04-19T13:19:54.403852+02:00  INFO pingora_core::server: Bootstrap done
2025-04-19T13:19:54.424489+02:00  INFO pingora_core::server: Server starting
PYTHON: Validating headers: MYLOCAL123 for proxy-bucket01...
2025-04-19T13:19:58.124729+02:00  INFO object_storage_proxy::utils::validator: Callback returned: false
PYTHON: Validating headers: MYLOCAL123 for proxy-bucket01...
2025-04-19T13:20:00.919320+02:00  INFO object_storage_proxy::utils::validator: Callback returned: true
2025-04-19T13:20:01.181775+02:00  INFO object_storage_proxy::credentials::secrets_proxy: No cached token found for proxy-bucket01, fetching ...
2025-04-19T13:20:01.181859+02:00  INFO object_storage_proxy::credentials::secrets_proxy: Fetching bearer token for the API key
2025-04-19T13:20:01.739385+02:00  INFO object_storage_proxy::credentials::secrets_proxy: Received access token
2025-04-19T13:20:01.739600+02:00  INFO object_storage_proxy::credentials::secrets_proxy: Fetched new token for proxy-bucket01
2025-04-19T13:20:01.739668+02:00  INFO object_storage_proxy: Sending request to upstream: https://proxy-bucket01.s3.eu-de.cloud-object-storage.appdomain.cloud/?list-type=2&prefix=&encoding-type=url
2025-04-19T13:20:01.739922+02:00  INFO object_storage_proxy: Request sent to upstream.

Status

  • pingora proxy implementation
  • pass in credentials handler
  • cache credentials
  • pass in bucket/instance and bucket/port config
  • split in workspace crate with core, cli and python crates (too many specifics for python)
  • config mgmt
  • cache authorization (with optional ttl)
  • http frontend
  • https frontend

Project details


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.1.11.tar.gz (47.7 kB 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.1.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.1.11-cp313-cp313-macosx_10_12_x86_64.whl (6.4 MB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

object_storage_proxy-0.1.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.1.11-cp312-cp312-macosx_10_12_x86_64.whl (6.4 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

object_storage_proxy-0.1.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

object_storage_proxy-0.1.11-cp311-cp311-macosx_10_12_x86_64.whl (6.4 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

object_storage_proxy-0.1.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11.tar.gz
Algorithm Hash digest
SHA256 1d0b4e0c405a63aee838042ff353009c9356fdda9e81101de6a41af40cc8de9b
MD5 8c362d5df6411d58cb9af1c8f8cc9b99
BLAKE2b-256 f2d60d550f7820a5377b6ed7057305825b4411c514eee09e2417fa32a3d89bc7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ab74e43b4982edba60dea577902f51f67106b294327a67dcb2b90572a20e0a68
MD5 bf96a689e03ca5120e3ba759b8b2c717
BLAKE2b-256 d4c09e382bf43149aa90c6e3ecbb116a430d9b8b984cc4bb2e9164d366f12013

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.1.11-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 027a543ea673619c42f2477058963d56d00540ef88a19eada468d5a23b89535d
MD5 4abf77ad1554cfce4982ea27d7b19a7b
BLAKE2b-256 3b9ad052eb705cc86d13702a9984ec322a778c7986024cceea30ae3af30c58da

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a4d93f20480d682c6b4a002e4d1bda9553bcb1a98ee0c45429285421f089ee47
MD5 607457aa3f14ff91ee8a587bfd4a88fb
BLAKE2b-256 3341a1eb5c7bd70a4dbc5f6e1dd47b5578c6213e435f05f0a8d6109a59a0af10

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.1.11-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 af573db10ee8e01a5e529097657964d29394045d1cfc70745dec58ebd55bbca0
MD5 c416c017014163647132fdf5f63fe9a3
BLAKE2b-256 24fd708208e8414c509e2ef9813eedd58607f2765cc96085ecf6a0049bcb24f6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 692f4e028afc36e34c00fcf2a563b821eaf5c5f1237153842f44aad2ee39fc92
MD5 189a684a881a99678b5461fc08031b63
BLAKE2b-256 ab677c015eab5b5fdf733ccf99ce9fce9fb50da67bd6cceb70561a7361317684

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.1.11-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 cdfd98cce91b60b89415d3f194d99a12e3d3c7d390eeffcd1862bc5a4ac78083
MD5 96e1a3fc65cf38bcef703e1e17b11950
BLAKE2b-256 6a6a92c5dfab30610013e079dd93956062886f05e8cd1e1553322247600c8691

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5bba28d50fc9a66d0dd6baf33fffaec978ae90ef1aafa769d7b27aac4f7bb67d
MD5 850418899dcaa2b4431ec4fdf9f42689
BLAKE2b-256 01ea4c99b0a59d86cf37d26d684762df549fa7c016986e4a969cbb7de92015bd

See more details on using hashes here.

File details

Details for the file object_storage_proxy-0.1.11-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 634645481e94ce80f13df8e395ba3470968d9f358fc53f2e0378ba1123b55cb0
MD5 fd0af04f29527aaadd6f6d10a3f73e0e
BLAKE2b-256 bbbd3f6e0118438741a671da20b04d81b201ce84774f4691d140f249da91fbb7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for object_storage_proxy-0.1.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 64036a9cc389ad7160614cd14e13c84cc18bf7684033635dfa3c140a4fb0c6ed
MD5 82886d610ee4f5e71638c3cd5c317b6c
BLAKE2b-256 1d85e3c95e76119f5373d79062d81fd108cf3e96dd5818431b57bfb8e97b907f

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