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.
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.gitignore +2 -1
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/Cargo.lock +1 -1
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/Cargo.toml +1 -1
- object_storage_proxy-0.3.3/LICENSE +16 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/PKG-INFO +40 -17
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/README.md +37 -15
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/pyproject.toml +2 -1
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/lib.rs +12 -0
- object_storage_proxy-0.3.1/LICENSE +0 -21
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.cargo/config.toml +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/.github/workflows/ci.yml +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/logo.svg +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/request_lifecycle.svg +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/img/request_stages.svg +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/requirements.txt +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/hmac_keystore.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/mod.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/models.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/secrets_proxy.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/credentials/signer.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/object_storage_proxy.pyi +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/cos_map.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/credentials.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/keystore.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/mod.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/parsers/path.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/utils/mod.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/src/utils/validator.rs +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/test_integration.sh +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/test_server.py +0 -0
- {object_storage_proxy-0.3.1 → object_storage_proxy-0.3.3}/uv.lock +0 -0
|
@@ -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.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
157
|
-
aws_secret_access_key = nothingmeaningful # <--
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
138
|
-
aws_secret_access_key = nothingmeaningful # <--
|
|
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
|
|
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 = "
|
|
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.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|