object-storage-proxy 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.gitignore +2 -1
  2. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/Cargo.lock +1 -1
  3. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/Cargo.toml +1 -1
  4. object_storage_proxy-0.3.3/LICENSE +16 -0
  5. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/PKG-INFO +40 -17
  6. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/README.md +37 -15
  7. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/pyproject.toml +2 -1
  8. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/lib.rs +12 -0
  9. object_storage_proxy-0.3.1/LICENSE +0 -21
  10. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.cargo/config.toml +0 -0
  11. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.github/workflows/ci.yml +0 -0
  12. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/logo.svg +0 -0
  13. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/request_lifecycle.svg +0 -0
  14. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/request_stages.svg +0 -0
  15. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/requirements.txt +0 -0
  16. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/hmac_keystore.rs +0 -0
  17. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/mod.rs +0 -0
  18. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/models.rs +0 -0
  19. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/secrets_proxy.rs +0 -0
  20. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/signer.rs +0 -0
  21. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/object_storage_proxy.pyi +0 -0
  22. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/cos_map.rs +0 -0
  23. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/credentials.rs +0 -0
  24. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/keystore.rs +0 -0
  25. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/mod.rs +0 -0
  26. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/path.rs +0 -0
  27. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/utils/mod.rs +0 -0
  28. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/utils/validator.rs +0 -0
  29. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/test_integration.sh +0 -0
  30. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/test_server.py +0 -0
  31. {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/uv.lock +0 -0
@@ -4,4 +4,5 @@
4
4
  .env
5
5
  .venv
6
6
  .DS_Store
7
- *.pem
7
+ *.pem
8
+ */with_*.log
@@ -1701,7 +1701,7 @@ dependencies = [
1701
1701
 
1702
1702
  [[package]]
1703
1703
  name = "object-storage-proxy"
1704
- version = "0.3.1"
1704
+ version = "0.3.3"
1705
1705
  dependencies = [
1706
1706
  "async-trait",
1707
1707
  "chrono",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "object-storage-proxy"
3
- version = "0.3.1"
3
+ version = "0.3.3"
4
4
  edition = "2024"
5
5
 
6
6
  [dependencies]
@@ -0,0 +1,16 @@
1
+ Personal Use License
2
+
3
+ Copyright (c) 2025 [Flexworks].
4
+
5
+ This software is free for private, personal, non-commercial use by individuals.
6
+
7
+ Commercial use, including use by companies, organizations, governments, or educational institutions, requires a paid commercial license.
8
+
9
+ You may not:
10
+ - Use this software in any organization, business, or government setting without a commercial license.
11
+ - Sell, sublicense, redistribute, or publicly host this software.
12
+ - Modify and distribute modifications of this software.
13
+
14
+ To obtain a commercial license, please contact: [jeroen@flexworks.eu].
15
+
16
+ All rights not explicitly granted are reserved by the copyright holder.
@@ -1,6 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: object-storage-proxy
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
+ Classifier: License :: Other/Proprietary License
4
5
  Classifier: Programming Language :: Rust
5
6
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
7
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -9,7 +10,7 @@ Requires-Dist: patchelf>=0.17.2.2 ; sys_platform == 'linux'
9
10
  License-File: LICENSE
10
11
  Summary: <object-storage-proxy ⚡> Yet Another Object Storage Proxy
11
12
  Author-email: Jeroen <jeroen@flexworks.eu>
12
- License: MIT
13
+ License: Personal Use License
13
14
  Requires-Python: >=3.10
14
15
  Description-Content-Type: text/markdown
15
16
  Project-URL: Homepage, https://github.com/opensourceworks-org/object-storage-proxy
@@ -30,16 +31,40 @@ Project-URL: BugTracker, https://github.com/opensourceworks-org/object-storage-p
30
31
 
31
32
  A fast and safe in-process reverse proxy server, based on Cloudflare's [pingora](https://github.com/cloudflare/pingora?tab=readme-ov-file), to reverse proxy AWS and IBM Cloud Object Storage buckets and integrate your Authentication and Authorization services.
32
33
 
33
- Decouples frontend from backend authentication and authorization.
34
+ - Compatible with AWS SDK -> aws cli/boto3, polars, spark, datafusion, ...
35
+ - Decouples frontend from backend authentication and authorization.
36
+ - Python interface: pass in callables for credentials fetching, validation, lookup secret for access_key (with cache).
37
+ - Compatibility Gateway between systems that support only 1 hmac credentials pair, and multi-credentials buckets backend.
34
38
 
35
39
 
36
- - [x] Takes a Python authorization callable (allows you to plug in your own authorization services) and api_key fetch callback function and cos bucket dictionary.
37
- - [x] The validation is cached with optional ttl (default 5min, keep it short).
38
- - [x] The apikey is used to authenticate against IBM's IAM endpoint and is cached and renewed on expiration. (IBM only)
39
- - [x] If no apikey or hmac keypair is provided, a Python function can be passed in to fetch the apikey or hmac keys for any given bucket (run once).
40
- - [x] HMAC support: passing in access and secret id keys (or as json string from python credentials callable), will be used to sign the upstream request (AWS/IBM/..)
41
- - [x] frontend request is signed with your own custom keypair
42
- - [x] supports running in cloud environments / proxy headers for request signature validation
40
+ ## Implementation
41
+ The Server Config accepts the following:
42
+
43
+ proxy_server_config = ProxyServerConfig(
44
+ cos_map=cos_map,
45
+ bucket_creds_fetcher=do_hmac_creds,
46
+ validator=do_validation,
47
+ http_port=6190,
48
+ https_port=8443,
49
+ threads=1,
50
+ verify=False,
51
+ hmac_keystore=hmac_keys,
52
+ skip_signature_validation=False,
53
+ hmac_fetcher=lookup_secret_key
54
+ )
55
+
56
+ | argument | description | optional | default value |
57
+ | -------- | ----------- | -------- | ------------- |
58
+ | cos_map | bucket configuration, see below | | NA |
59
+ | bucket_creds_fetcher | python callable to retrieve credentials for a given bucket, to return either api key or hmac key pair | ✅ | NA |
60
+ | validator | python callable, validates access for a given token/bucket combination | ✅ | NA |
61
+ | http_port | server listener port on http | ✅ at least http_port or https_port, or both | NA |
62
+ | https_port | server listener port on https | ✅ at least http_port or https_port, or both | NA |
63
+ | threads | number of service threads | ✅ | 1 |
64
+ | verify | ignore ssl verification errors on backend storage (IBM/AWS) (for dev purposes) | ✅ | False |
65
+ | hmac_keystore | | | |
66
+ | skip_signature_validation | ignore ssl verification errors on frontend (for dev purposes) | ✅ | False |
67
+
43
68
 
44
69
  The bucket dict contains for each bucket:
45
70
 
@@ -81,6 +106,7 @@ cos_map = {
81
106
  ```
82
107
 
83
108
  The Python callables take two arguments:
109
+ TODO: add prefix for fine-grained validation
84
110
 
85
111
  - token: parsed from the original aws request's authorization header
86
112
  - bucket: parsed from the uri path
@@ -90,11 +116,8 @@ The Python callables take two arguments:
90
116
  def your_request_authorizer(token: str, bucket: str) -> bool
91
117
  ```
92
118
 
93
- Proxy Configuration
94
-
95
-
96
-
97
119
 
120
+ ## The Problem
98
121
 
99
122
  ### secrets
100
123
  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.
@@ -153,8 +176,8 @@ s3 =
153
176
  ~/.aws/credentials
154
177
  ```ini
155
178
  [osp]
156
- aws_access_key_id = MYLOCAL123 # <-- this could be an openid connect/oauth2 token or anything that makes sense for your business, encode it if required
157
- aws_secret_access_key = nothingmeaningful # <-- used for compatibility with aws sdk, to sign original request, but is ignored later
179
+ aws_access_key_id = MYLOCAL123 # <-- this could be an internal client identifier, to fetch openid connect/oauth2 token or anything that makes sense for your business
180
+ aws_secret_access_key = nothingmeaningful # <-- private key to sign original request
158
181
  ```
159
182
 
160
183
  Set up a minimal server implementation:
@@ -224,7 +247,7 @@ def lookup_secret_key(access_key: str) -> str | None:
224
247
  def do_validation(token: str, bucket: str) -> bool:
225
248
  """ Authorize the request based on token for the given bucket.
226
249
  You can plug in your own authorization service here.
227
- The token is the authorization token passed in the request.
250
+ The token is a client identifier used to fetch an authorization token and further authenticate/authorize.
228
251
  The bucket is the bucket name.
229
252
  The function should return True if the request is authorized, False otherwise.
230
253
  """
@@ -11,16 +11,40 @@
11
11
 
12
12
  A fast and safe in-process reverse proxy server, based on Cloudflare's [pingora](https://github.com/cloudflare/pingora?tab=readme-ov-file), to reverse proxy AWS and IBM Cloud Object Storage buckets and integrate your Authentication and Authorization services.
13
13
 
14
- Decouples frontend from backend authentication and authorization.
14
+ - Compatible with AWS SDK -> aws cli/boto3, polars, spark, datafusion, ...
15
+ - Decouples frontend from backend authentication and authorization.
16
+ - Python interface: pass in callables for credentials fetching, validation, lookup secret for access_key (with cache).
17
+ - Compatibility Gateway between systems that support only 1 hmac credentials pair, and multi-credentials buckets backend.
15
18
 
16
19
 
17
- - [x] Takes a Python authorization callable (allows you to plug in your own authorization services) and api_key fetch callback function and cos bucket dictionary.
18
- - [x] The validation is cached with optional ttl (default 5min, keep it short).
19
- - [x] The apikey is used to authenticate against IBM's IAM endpoint and is cached and renewed on expiration. (IBM only)
20
- - [x] If no apikey or hmac keypair is provided, a Python function can be passed in to fetch the apikey or hmac keys for any given bucket (run once).
21
- - [x] HMAC support: passing in access and secret id keys (or as json string from python credentials callable), will be used to sign the upstream request (AWS/IBM/..)
22
- - [x] frontend request is signed with your own custom keypair
23
- - [x] supports running in cloud environments / proxy headers for request signature validation
20
+ ## Implementation
21
+ The Server Config accepts the following:
22
+
23
+ proxy_server_config = ProxyServerConfig(
24
+ cos_map=cos_map,
25
+ bucket_creds_fetcher=do_hmac_creds,
26
+ validator=do_validation,
27
+ http_port=6190,
28
+ https_port=8443,
29
+ threads=1,
30
+ verify=False,
31
+ hmac_keystore=hmac_keys,
32
+ skip_signature_validation=False,
33
+ hmac_fetcher=lookup_secret_key
34
+ )
35
+
36
+ | argument | description | optional | default value |
37
+ | -------- | ----------- | -------- | ------------- |
38
+ | cos_map | bucket configuration, see below | | NA |
39
+ | bucket_creds_fetcher | python callable to retrieve credentials for a given bucket, to return either api key or hmac key pair | ✅ | NA |
40
+ | validator | python callable, validates access for a given token/bucket combination | ✅ | NA |
41
+ | http_port | server listener port on http | ✅ at least http_port or https_port, or both | NA |
42
+ | https_port | server listener port on https | ✅ at least http_port or https_port, or both | NA |
43
+ | threads | number of service threads | ✅ | 1 |
44
+ | verify | ignore ssl verification errors on backend storage (IBM/AWS) (for dev purposes) | ✅ | False |
45
+ | hmac_keystore | | | |
46
+ | skip_signature_validation | ignore ssl verification errors on frontend (for dev purposes) | ✅ | False |
47
+
24
48
 
25
49
  The bucket dict contains for each bucket:
26
50
 
@@ -62,6 +86,7 @@ cos_map = {
62
86
  ```
63
87
 
64
88
  The Python callables take two arguments:
89
+ TODO: add prefix for fine-grained validation
65
90
 
66
91
  - token: parsed from the original aws request's authorization header
67
92
  - bucket: parsed from the uri path
@@ -71,11 +96,8 @@ The Python callables take two arguments:
71
96
  def your_request_authorizer(token: str, bucket: str) -> bool
72
97
  ```
73
98
 
74
- Proxy Configuration
75
-
76
-
77
-
78
99
 
100
+ ## The Problem
79
101
 
80
102
  ### secrets
81
103
  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.
@@ -134,8 +156,8 @@ s3 =
134
156
  ~/.aws/credentials
135
157
  ```ini
136
158
  [osp]
137
- aws_access_key_id = MYLOCAL123 # <-- this could be an openid connect/oauth2 token or anything that makes sense for your business, encode it if required
138
- aws_secret_access_key = nothingmeaningful # <-- used for compatibility with aws sdk, to sign original request, but is ignored later
159
+ aws_access_key_id = MYLOCAL123 # <-- this could be an internal client identifier, to fetch openid connect/oauth2 token or anything that makes sense for your business
160
+ aws_secret_access_key = nothingmeaningful # <-- private key to sign original request
139
161
  ```
140
162
 
141
163
  Set up a minimal server implementation:
@@ -205,7 +227,7 @@ def lookup_secret_key(access_key: str) -> str | None:
205
227
  def do_validation(token: str, bucket: str) -> bool:
206
228
  """ Authorize the request based on token for the given bucket.
207
229
  You can plug in your own authorization service here.
208
- The token is the authorization token passed in the request.
230
+ The token is a client identifier used to fetch an authorization token and further authenticate/authorize.
209
231
  The bucket is the bucket name.
210
232
  The function should return True if the request is authorized, False otherwise.
211
233
  """
@@ -7,11 +7,12 @@ name = "object-storage-proxy"
7
7
  description = "<object-storage-proxy ⚡> Yet Another Object Storage Proxy"
8
8
  readme = { file = "README.md", content-type = "text/markdown" }
9
9
  authors = [{ name = "Jeroen", email = "jeroen@flexworks.eu" }]
10
- license = "MIT"
10
+ license = "Personal Use License"
11
11
 
12
12
 
13
13
  requires-python = ">=3.10"
14
14
  classifiers = [
15
+ "License :: Other/Proprietary License",
15
16
  "Programming Language :: Rust",
16
17
  "Programming Language :: Python :: Implementation :: CPython",
17
18
  "Programming Language :: Python :: Implementation :: PyPy",
@@ -7,6 +7,7 @@ use http::uri::Authority;
7
7
  use parsers::cos_map::{CosMapItem, parse_cos_map};
8
8
  use parsers::keystore::parse_hmac_list;
9
9
  use pingora::http::ResponseHeader;
10
+ use pingora::protocols::ALPN;
10
11
  use pingora::Result;
11
12
  use pingora::proxy::{ProxyHttp, Session};
12
13
  use pingora::server::Server;
@@ -268,6 +269,17 @@ impl ProxyHttp for MyProxy {
268
269
  let addr = (endpoint.clone(), port);
269
270
 
270
271
  let mut peer = Box::new(HttpPeer::new(addr, true, endpoint.clone()));
272
+ peer.options.alpn = ALPN::H2;
273
+
274
+ peer.options.max_h2_streams = 32;
275
+ peer.options.h2_ping_interval = Some(Duration::from_secs(30));
276
+
277
+ // todo: make ths configurable
278
+
279
+ // peer.options.idle_timeout = Some(Duration::from_secs(300));
280
+ // peer.options.connection_timeout = Some(Duration::from_secs(30));
281
+ // peer.options.read_timeout = Some(Duration::from_secs(300));
282
+ // peer.options.write_timeout = Some(Duration::from_secs(300));
271
283
 
272
284
  debug!("peer: {:#?}", &peer);
273
285
 
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Jeroen Van Renterghem
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.