8000 Fixed IAM requests sent with wrong account ID to moto (#1399) · sharp-bits/localstack@2e0d398 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2e0d398

Browse files
acsbendiwhummer
authored andcommitted
Fixed IAM requests sent with wrong account ID to moto (localstack#1399)
1 parent ecb97fa commit 2e0d398

File tree

3 files changed

+68
-22
lines changed

3 files changed

+68
-22
lines changed

localstack/services/iam/iam_listener.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import re
2-
from localstack.constants import TEST_AWS_ACCOUNT_ID
2+
from requests.models import Request
3+
from localstack.constants import TEST_AWS_ACCOUNT_ID, MOTO_ACCOUNT_ID
4+
from localstack.utils.aws import aws_stack
35
from localstack.utils.common import to_str
46
from localstack.services.generic_proxy import ProxyListener
57

68

79
class ProxyListenerIAM(ProxyListener):
810

11+
def forward_request(self, method, path, data, headers):
12+
if method == 'POST' and path == '/':
13+
data = self._reset_account_id(data)
14+
return Request(data=data, headers=headers, method=method)
15+
16+
return True
17+
918
def return_response(self, method, path, data, headers, response):
1019

1120
if response.content:
@@ -23,10 +32,17 @@ def _fix_date_format(self, response):
2332
self._replace(response, pattern, replacement)
2433

2534
def _fix_account_id(self, response):
26-
pattern = r'<Arn>\s*arn:aws:iam::([0-9]+):([^<]+)</Arn>'
27-
replacement = r'<Arn>arn:aws:iam::%s:\2</Arn>' % TEST_AWS_ACCOUNT_ID
35+
pattern = r'<([^>]*)Arn>\s*arn:aws:iam::([0-9]+):([^<]+)</\1Arn>'
36+
replacement = r'<\1Arn>arn:aws:iam::%s:\3</\1Arn>' % TEST_AWS_ACCOUNT_ID
2837
self._replace(response, pattern, replacement)
2938

39+
def _reset_account_id(self, data):
40+
""" Fix account ID in request payload. All external-facing responses contain our
41+
predefined account ID (defaults to 000000000000), whereas the backend endpoint
42+
from moto expects a different hardcoded account ID (123456789012). """
43+
return aws_stack.fix_account_id_in_arns(
44+
data, colon_delimiter='%3A', existing=TEST_AWS_ACCOUNT_ID, replace=MOTO_ACCOUNT_ID)
45+
3046
def _replace(self, response, pattern, replacement):
3147
content = to_str(response.content)
3248
response._content = re.sub(pattern, replacement, content)

localstack/utils/aws/aws_stack.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def fix_account_id_in_arns(response, colon_delimiter=':', existing=None, replace
255255

256256
replace = r'arn{col}aws{col}\1{col}\2{col}{acc}{col}'.format(col=colon_delimiter, acc=replace)
257257
for acc_id in existing:
258-
regex = r'arn{col}aws{col}([^:%]+){col}([^:%]+){col}{acc}{col}'.format(col=colon_delimiter, acc=acc_id)
258+
regex = r'arn{col}aws{col}([^:%]+){col}([^:%]*){col}{acc}{col}'.format(col=colon_delimiter, acc=acc_id)
259259
content = re.sub(regex, replace, content)
260260

261261
if not is_str_obj:
Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,53 @@
11
import os
22
import logging
3+
import json
4+
import unittest
5+
6+
from localstack.constants import TEST_AWS_ACCOUNT_ID
7+
from localstack.utils.aws import aws_stack
38
from localstack.utils.kinesis import kinesis_connector
49

510

6-
def run_kcl_with_iam_assume_role():
7-
env_vars = {}
8-
if os.environ.get('AWS_ASSUME_ROLE_ARN'):
9-
env_vars['AWS_ASSUME_ROLE_ARN'] = os.environ.get('AWS_ASSUME_ROLE_ARN')
10-
env_vars['AWS_ASSUME_ROLE_SESSION_NAME'] = os.environ.get('AWS_ASSUME_ROLE_SESSION_NAME')
11-
env_vars['ENV'] = os.environ.get('ENV') or 'main'
12-
13-
def process_records(records):
14-
print(records)
15-
16-
# start Kinesis client
17-
stream_name = 'test-foobar'
18-
kinesis_connector.listen_to_kinesis(
19-
stream_name=stream_name,
20-
listener_func=process_records,
21-
env_vars=env_vars,
22-
kcl_log_level=logging.INFO,
23-
wait_until_started=True)
11+
class TestIAMIntegrations(unittest.TestCase):
12+
13+
def test_run_kcl_with_iam_assume_role(self):
14+
env_vars = {}
15+
if os.environ.get('AWS_ASSUME_ROLE_ARN'):
16+
env_vars['AWS_ASSUME_ROLE_ARN'] = os.environ.get('AWS_ASSUME_ROLE_ARN')
17+
env_vars['AWS_ASSUME_ROLE_SESSION_NAME'] = os.environ.get('AWS_ASSUME_ROLE_SESSION_NAME')
18+
env_vars['ENV'] = os.environ.get('ENV') or 'main'
19+
20+
def process_records(records):
21+
print(records)
22+
23+
# start Kinesis client
24+
stream_name = 'test-foobar'
25+
kinesis_connector.listen_to_kinesis(
26+
stream_name=stream_name,
27+
listener_func=process_records,
28+
env_vars=env_vars,
29+
kcl_log_level=logging.INFO,
30+
wait_until_started=True)
31+
32+
def test_attach_iam_role_to_new_iam_user(self):
33+
test_policy_document = {
34+
'Version': '2012-10-17',
35+
'Statement': {
36+
'Effect': 'Allow',
37+
'Action': 's3:ListBucket',
38+
'Resource': 'arn:aws:s3:::example_bucket'
39+
}
40+
}
41+
test_user_name = 'test-user'
42+
43+
iam_client = aws_stack.connect_to_service('iam')
44+
45+
iam_client.create_user(UserName=test_user_name)
46+
response = iam_client.create_policy(PolicyName='test-policy',
47+
PolicyDocument=json.dumps(test_policy_document))
48+
test_policy_arn = response['Policy']['Arn']
49+
self.assertIn(TEST_AWS_ACCOUNT_ID, test_policy_arn)
50+
iam_client.attach_user_policy(UserName=test_user_name, PolicyArn=test_policy_arn)
51+
attached_user_policies = iam_client.list_attached_user_policies(UserName=test_user_name)
52+
self.assertEqual(len(attached_user_policies['AttachedPolicies']), 1)
53+
self.assertEqual(attached_user_policies['AttachedPolicies'][0]['PolicyArn'], test_policy_arn)

0 commit comments

Comments
 (0)
0