Skip to content

Commit f10102f

Browse files
authoredOct 14, 2024··
fix logic to proxy S3 requests against *amazonaws.com (#83)
1 parent c11b6a9 commit f10102f

File tree

5 files changed

+27
-10
lines changed

5 files changed

+27
-10
lines changed
 

‎aws-replicator/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ install: venv
3333
$(VENV_RUN); $(PIP_CMD) install -e ".[test]"
3434

3535
test: venv
36-
$(VENV_RUN); python -m pytest $(TEST_PATH)
36+
$(VENV_RUN); python -m pytest $(PYTEST_ARGS) $(TEST_PATH)
3737

3838
dist: venv
3939
$(VENV_RUN); python setup.py sdist bdist_wheel

‎aws-replicator/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ If you wish to access the deprecated instructions, they can be found [here](http
126126

127127
## Change Log
128128

129+
* `0.1.20`: Fix logic for proxying S3 requests with `*.s3.amazonaws.com` host header
129130
* `0.1.19`: Print human-readable message for invalid regexes in resource configs; fix logic for proxying S3 requests with host-based addressing
130131
* `0.1.18`: Update environment check to use SDK Docker client and enable starting the proxy from within Docker (e.g., from the LS main container as part of an init script)
131132
* `0.1.17`: Add basic support for ARN-based pattern-matching for `secretsmanager` resources

‎aws-replicator/aws_replicator/client/auth_proxy.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,10 @@ def _fix_headers(self, request: Request, service_name: str):
275275
def _fix_host_and_path(self, request: Request, service_name: str):
276276
if service_name == "s3":
277277
# fix the path and prepend the bucket name, to avoid bucket addressing issues
278+
regex_base_domain = rf"((amazonaws\.com)|({LOCALHOST_HOSTNAME}))"
278279
host = request.headers.pop(HEADER_HOST_ORIGINAL, None)
279280
host = host or request.headers.get("Host") or ""
280-
match = re.match(rf"(.+)\.s3\.{LOCALHOST_HOSTNAME}", host)
281+
match = re.match(rf"(.+)\.s3\.{regex_base_domain}", host)
281282
if match:
282283
# prepend the bucket name (extracted from the host) to the path of the request (path-based addressing)
283284
request.path = f"/{match.group(1)}{request.path}"

‎aws-replicator/setup.cfg

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[metadata]
22
name = localstack-extension-aws-replicator
3-
version = 0.1.19
4-
summary = LocalStack Extension: AWS replicator
5-
description = Replicate AWS resources into your LocalStack instance
3+
version = 0.1.20
4+
summary = LocalStack AWS Proxy Extension
5+
description = Proxy AWS resources into your LocalStack instance
66
long_description = file: README.md
77
long_description_content_type = text/markdown; charset=UTF-8
88
url = https://github.com/localstack/localstack-extensions/tree/main/aws-replicator

‎aws-replicator/tests/test_proxy_requests.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Note: these tests depend on the extension being installed and actual AWS credentials being configured, such
22
# that the proxy can be started within the tests. They are designed to be mostly run in CI at this point.
33
import gzip
4+
import re
5+
from urllib.parse import urlparse
46

57
import boto3
68
import pytest
@@ -41,20 +43,33 @@ def _start(config: dict = None):
4143

4244

4345
@pytest.mark.parametrize("metadata_gzip", [True, False])
44-
@pytest.mark.parametrize("host_addressing", [True, False])
45-
def test_s3_requests(start_aws_proxy, s3_create_bucket, metadata_gzip, host_addressing):
46+
@pytest.mark.parametrize("target_endpoint", ["local_domain", "aws_domain", "default"])
47+
def test_s3_requests(start_aws_proxy, s3_create_bucket, metadata_gzip, target_endpoint):
4648
# start proxy
4749
config = ProxyConfig(services={"s3": {"resources": ".*"}}, bind_host=PROXY_BIND_HOST)
4850
start_aws_proxy(config)
4951

5052
# create clients
51-
if host_addressing:
53+
if target_endpoint == "default":
54+
s3_client = connect_to().s3
55+
else:
5256
s3_client = connect_to(
5357
endpoint_url="http://s3.localhost.localstack.cloud:4566",
5458
config=Config(s3={"addressing_style": "virtual"}),
5559
).s3
56-
else:
57-
s3_client = connect_to().s3
60+
61+
if target_endpoint == "aws_domain":
62+
63+
def _add_header(request, **kwargs):
64+
# instrument boto3 client to add custom `Host` header, mimicking a `*.s3.amazonaws.com` request
65+
url = urlparse(request.url)
66+
match = re.match(r"(.+)\.s3\.localhost\.localstack\.cloud", url.netloc)
67+
if match:
68+
request.headers.add_header("host", f"{match.group(1)}.s3.amazonaws.com")
69+
70+
s3_client.meta.events.register_first("before-sign.*.*", _add_header)
71+
72+
# define S3 client pointing to real AWS
5873
s3_client_aws = boto3.client("s3")
5974

6075
# list buckets to assert that proxy is up and running

0 commit comments

Comments
 (0)
Please sign in to comment.