Commit 4fe2b3c7 authored by Yuan Gao's avatar Yuan Gao
Browse files

Encode IAM role name to UTF-8

* Officially support debian10
* Ignore libwrap efs_config for CentOS8
parent 41cd0384
...@@ -14,6 +14,7 @@ The `efs-utils` package has been verified against the following Linux distributi ...@@ -14,6 +14,7 @@ The `efs-utils` package has been verified against the following Linux distributi
| RHEL 7 | `rpm`| `systemd` | | RHEL 7 | `rpm`| `systemd` |
| RHEL 8 | `rpm`| `systemd` | | RHEL 8 | `rpm`| `systemd` |
| Debian 9 | `deb` | `systemd` | | Debian 9 | `deb` | `systemd` |
| Debian 10 | `deb` | `systemd` |
| Ubuntu 16.04 | `deb` | `systemd` | | Ubuntu 16.04 | `deb` | `systemd` |
| Ubuntu 18.04 | `deb` | `systemd` | | Ubuntu 18.04 | `deb` | `systemd` |
......
...@@ -198,6 +198,8 @@ STUNNEL_EFS_CONFIG = { ...@@ -198,6 +198,8 @@ STUNNEL_EFS_CONFIG = {
WATCHDOG_SERVICE = 'amazon-efs-mount-watchdog' WATCHDOG_SERVICE = 'amazon-efs-mount-watchdog'
SYSTEM_RELEASE_PATH = '/etc/system-release' SYSTEM_RELEASE_PATH = '/etc/system-release'
RHEL8_RELEASE_NAME = 'Red Hat Enterprise Linux release 8' RHEL8_RELEASE_NAME = 'Red Hat Enterprise Linux release 8'
CENTOS8_RELEASE_NAME = 'CentOS Linux release 8'
SKIP_NO_LIBWRAP_RELEASES = [RHEL8_RELEASE_NAME, CENTOS8_RELEASE_NAME]
def fatal_error(user_message, log_message=None, exit_code=1): def fatal_error(user_message, log_message=None, exit_code=1):
...@@ -376,10 +378,10 @@ def get_aws_security_credentials_from_ecs(aws_creds_uri, is_fatal=False): ...@@ -376,10 +378,10 @@ def get_aws_security_credentials_from_ecs(aws_creds_uri, is_fatal=False):
def get_aws_security_credentials_from_instance_metadata(iam_role_name): def get_aws_security_credentials_from_instance_metadata(iam_role_name):
security_creds_lookup_url = INSTANCE_IAM_URL + str(iam_role_name) security_creds_lookup_url = INSTANCE_IAM_URL + iam_role_name
unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % security_creds_lookup_url unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % security_creds_lookup_url
url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.',\ url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.' % \
security_creds_lookup_url, SECURITY_CREDS_IAM_ROLE_HELP_URL (security_creds_lookup_url, SECURITY_CREDS_IAM_ROLE_HELP_URL)
iam_security_dict = url_request_helper(security_creds_lookup_url, unsuccessful_resp, url_error_msg) iam_security_dict = url_request_helper(security_creds_lookup_url, unsuccessful_resp, url_error_msg)
if iam_security_dict and all(k in iam_security_dict for k in CREDENTIALS_KEYS): if iam_security_dict and all(k in iam_security_dict for k in CREDENTIALS_KEYS):
...@@ -390,8 +392,8 @@ def get_aws_security_credentials_from_instance_metadata(iam_role_name): ...@@ -390,8 +392,8 @@ def get_aws_security_credentials_from_instance_metadata(iam_role_name):
def get_iam_role_name(): def get_iam_role_name():
iam_role_unsuccessful_resp = 'Unsuccessful retrieval of IAM role name at %s.' % INSTANCE_IAM_URL iam_role_unsuccessful_resp = 'Unsuccessful retrieval of IAM role name at %s.' % INSTANCE_IAM_URL
iam_role_url_error_msg = 'Unable to reach %s to retrieve IAM role name. See %s for more info.', INSTANCE_IAM_URL, \ iam_role_url_error_msg = 'Unable to reach %s to retrieve IAM role name. See %s for more info.' % \
SECURITY_CREDS_IAM_ROLE_HELP_URL (INSTANCE_IAM_URL, SECURITY_CREDS_IAM_ROLE_HELP_URL)
iam_role_name = url_request_helper(INSTANCE_IAM_URL, iam_role_unsuccessful_resp, iam_role_url_error_msg) iam_role_name = url_request_helper(INSTANCE_IAM_URL, iam_role_unsuccessful_resp, iam_role_url_error_msg)
return iam_role_name return iam_role_name
...@@ -456,16 +458,17 @@ def url_request_helper(url, unsuccessful_resp, url_error_msg): ...@@ -456,16 +458,17 @@ def url_request_helper(url, unsuccessful_resp, url_error_msg):
return None return None
resp_body = request_resp.read() resp_body = request_resp.read()
resp_body_type = type(resp_body)
try: try:
if type(resp_body) is str: if resp_body_type is str:
resp_dict = json.loads(resp_body) resp_dict = json.loads(resp_body)
else: else:
resp_dict = json.loads(resp_body.decode(request_resp.headers.get_content_charset() or 'us-ascii')) resp_dict = json.loads(resp_body.decode(request_resp.headers.get_content_charset() or 'us-ascii'))
return resp_dict return resp_dict
except ValueError as e: except ValueError as e:
logging.debug('Error parsing json: %s, returning raw response body: %s' % (e, str(resp_body))) logging.info('ValueError parsing "%s" into json: %s. Returning response body.' % (str(resp_body), e))
return resp_body return resp_body if resp_body_type is str else resp_body.decode('utf-8')
except URLError as e: except URLError as e:
logging.debug('%s %s', url_error_msg, e) logging.debug('%s %s', url_error_msg, e)
return None return None
...@@ -670,7 +673,8 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por ...@@ -670,7 +673,8 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por
else: else:
fatal_error(tls_controls_message % 'stunnel_check_cert_validity') fatal_error(tls_controls_message % 'stunnel_check_cert_validity')
if RHEL8_RELEASE_NAME not in get_system_release_version(): system_release_version = get_system_release_version()
if not any(release in system_release_version for release in SKIP_NO_LIBWRAP_RELEASES):
efs_config['libwrap'] = 'no' efs_config['libwrap'] = 'no'
stunnel_config = '\n'.join(serialize_stunnel_config(global_config) + serialize_stunnel_config(efs_config, 'efs')) stunnel_config = '\n'.join(serialize_stunnel_config(global_config) + serialize_stunnel_config(efs_config, 'efs'))
......
...@@ -175,8 +175,8 @@ def get_aws_security_credentials_from_ecs(uri): ...@@ -175,8 +175,8 @@ def get_aws_security_credentials_from_ecs(uri):
dict_keys = ['AccessKeyId', 'SecretAccessKey', 'Token'] dict_keys = ['AccessKeyId', 'SecretAccessKey', 'Token']
ecs_uri = ECS_TASK_METADATA_API + uri ecs_uri = ECS_TASK_METADATA_API + uri
ecs_unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % ecs_uri ecs_unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % ecs_uri
ecs_url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.', ecs_uri, \ ecs_url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.' % \
SECURITY_CREDS_ECS_URI_HELP_URL (ecs_uri, SECURITY_CREDS_ECS_URI_HELP_URL)
ecs_security_dict = url_request_helper(ecs_uri, ecs_unsuccessful_resp, ecs_url_error_msg) ecs_security_dict = url_request_helper(ecs_uri, ecs_unsuccessful_resp, ecs_url_error_msg)
if ecs_security_dict and all(k in ecs_security_dict for k in dict_keys): if ecs_security_dict and all(k in ecs_security_dict for k in dict_keys):
...@@ -189,14 +189,14 @@ def get_aws_security_credentials_from_instance_metadata(): ...@@ -189,14 +189,14 @@ def get_aws_security_credentials_from_instance_metadata():
# through IAM role name security credentials lookup uri (after lookup for IAM role name attached to instance) # through IAM role name security credentials lookup uri (after lookup for IAM role name attached to instance)
dict_keys = ['AccessKeyId', 'SecretAccessKey', 'Token'] dict_keys = ['AccessKeyId', 'SecretAccessKey', 'Token']
iam_role_unsuccessful_resp = 'Unsuccessful retrieval of IAM role name at %s.' % INSTANCE_IAM_URL iam_role_unsuccessful_resp = 'Unsuccessful retrieval of IAM role name at %s.' % INSTANCE_IAM_URL
iam_role_url_error_msg = 'Unable to reach %s to retrieve IAM role name. See %s for more info.', INSTANCE_IAM_URL, \ iam_role_url_error_msg = 'Unable to reach %s to retrieve IAM role name. See %s for more info.' % \
SECURITY_CREDS_IAM_ROLE_HELP_URL (INSTANCE_IAM_URL, SECURITY_CREDS_IAM_ROLE_HELP_URL)
iam_role_name = url_request_helper(INSTANCE_IAM_URL, iam_role_unsuccessful_resp, iam_role_url_error_msg) iam_role_name = url_request_helper(INSTANCE_IAM_URL, iam_role_unsuccessful_resp, iam_role_url_error_msg)
if iam_role_name: if iam_role_name:
security_creds_lookup_url = INSTANCE_IAM_URL + str(iam_role_name) security_creds_lookup_url = INSTANCE_IAM_URL + iam_role_name
unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % security_creds_lookup_url unsuccessful_resp = 'Unsuccessful retrieval of AWS security credentials at %s.' % security_creds_lookup_url
url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.', \ url_error_msg = 'Unable to reach %s to retrieve AWS security credentials. See %s for more info.' % \
security_creds_lookup_url, SECURITY_CREDS_IAM_ROLE_HELP_URL (security_creds_lookup_url, SECURITY_CREDS_IAM_ROLE_HELP_URL)
iam_security_dict = url_request_helper(security_creds_lookup_url, unsuccessful_resp, url_error_msg) iam_security_dict = url_request_helper(security_creds_lookup_url, unsuccessful_resp, url_error_msg)
if iam_security_dict and all(k in iam_security_dict for k in dict_keys): if iam_security_dict and all(k in iam_security_dict for k in dict_keys):
...@@ -240,17 +240,17 @@ def url_request_helper(url, unsuccessful_resp, url_error_msg): ...@@ -240,17 +240,17 @@ def url_request_helper(url, unsuccessful_resp, url_error_msg):
return None return None
resp_body = request_resp.read() resp_body = request_resp.read()
resp_body_type = type(resp_body)
try: try:
if type(resp_body) is str: if resp_body_type is str:
resp_dict = json.loads(resp_body) resp_dict = json.loads(resp_body)
else: else:
resp_dict = json.loads(resp_body.decode(request_resp.headers.get_content_charset() or 'us-ascii')) resp_dict = json.loads(resp_body.decode(request_resp.headers.get_content_charset() or 'us-ascii'))
return resp_dict return resp_dict
except ValueError as e: except ValueError as e:
logging.debug('Error parsing json: %s, returning raw response body: %s' % (e, str(resp_body))) logging.info('ValueError parsing "%s" into json: %s. Returning response body.' % (str(resp_body), e))
return resp_body return resp_body if resp_body_type is str else resp_body.decode('utf-8')
except URLError as e: except URLError as e:
logging.debug('%s %s', url_error_msg, e) logging.debug('%s %s', url_error_msg, e)
return None return None
......
...@@ -157,7 +157,7 @@ def test_get_aws_security_credentials_get_ecs_from_option_url(mocker): ...@@ -157,7 +157,7 @@ def test_get_aws_security_credentials_get_ecs_from_option_url(mocker):
assert credentials_source == 'ecs:' + AWSCREDSURI assert credentials_source == 'ecs:' + AWSCREDSURI
def test_get_aws_security_credentials_get_instance_metadata(mocker): def test_get_aws_security_credentials_get_instance_metadata_role_name_str(mocker):
mocker.patch.dict(os.environ, {}) mocker.patch.dict(os.environ, {})
mocker.patch('os.path.exists', return_value=False) mocker.patch('os.path.exists', return_value=False)
response = json.dumps({ response = json.dumps({
...@@ -169,7 +169,31 @@ def test_get_aws_security_credentials_get_instance_metadata(mocker): ...@@ -169,7 +169,31 @@ def test_get_aws_security_credentials_get_instance_metadata(mocker):
'Token': SESSION_TOKEN_VAL, 'Token': SESSION_TOKEN_VAL,
'Expiration': '2019-10-25T21:17:24Z' 'Expiration': '2019-10-25T21:17:24Z'
}) })
mocker.patch('mount_efs.urlopen', return_value=MockUrlLibResponse(data=response)) side_effects = [MockUrlLibResponse(data='FAKE_IAM_ROLE_NAME'), MockUrlLibResponse(data=response)]
mocker.patch('mount_efs.urlopen', side_effect=side_effects)
credentials, credentials_source = mount_efs.get_aws_security_credentials(True, None)
assert credentials['AccessKeyId'] == ACCESS_KEY_ID_VAL
assert credentials['SecretAccessKey'] == SECRET_ACCESS_KEY_VAL
assert credentials['Token'] == SESSION_TOKEN_VAL
assert credentials_source == 'metadata:'
def test_get_aws_security_credentials_get_instance_metadata_role_name_bytes(mocker):
mocker.patch.dict(os.environ, {})
mocker.patch('os.path.exists', return_value=False)
response = json.dumps({
'Code': 'Success',
'LastUpdated': '2019-10-25T14:41:42Z',
'Type': 'AWS-HMAC',
'AccessKeyId': ACCESS_KEY_ID_VAL,
'SecretAccessKey': SECRET_ACCESS_KEY_VAL,
'Token': SESSION_TOKEN_VAL,
'Expiration': '2019-10-25T21:17:24Z'
})
side_effects = [MockUrlLibResponse(data=b'FAKE_IAM_ROLE_NAME'), MockUrlLibResponse(data=response)]
mocker.patch('mount_efs.urlopen', side_effect=side_effects)
credentials, credentials_source = mount_efs.get_aws_security_credentials(True, None) credentials, credentials_source = mount_efs.get_aws_security_credentials(True, None)
......
...@@ -165,7 +165,7 @@ def test_get_aws_security_credentials_ecs(mocker): ...@@ -165,7 +165,7 @@ def test_get_aws_security_credentials_ecs(mocker):
assert credentials['Token'] == SESSION_TOKEN_VAL assert credentials['Token'] == SESSION_TOKEN_VAL
def test_get_aws_security_credentials_instance_metadata(mocker): def test_get_aws_security_credentials_instance_metadata_role_name_str(mocker):
mocker.patch.dict(os.environ, {}) mocker.patch.dict(os.environ, {})
mocker.patch('os.path.exists', return_value=False) mocker.patch('os.path.exists', return_value=False)
response = json.dumps({ response = json.dumps({
...@@ -177,7 +177,30 @@ def test_get_aws_security_credentials_instance_metadata(mocker): ...@@ -177,7 +177,30 @@ def test_get_aws_security_credentials_instance_metadata(mocker):
'Token': SESSION_TOKEN_VAL, 'Token': SESSION_TOKEN_VAL,
'Expiration': '2019-10-25T21:17:24Z' 'Expiration': '2019-10-25T21:17:24Z'
}) })
mocker.patch('watchdog.urlopen', return_value=MockUrlLibResponse(data=response)) side_effects = [MockUrlLibResponse(data='FAKE_IAM_ROLE_NAME'), MockUrlLibResponse(data=response)]
mocker.patch('watchdog.urlopen', side_effect=side_effects)
credentials = watchdog.get_aws_security_credentials('metadata:')
assert credentials['AccessKeyId'] == ACCESS_KEY_ID_VAL
assert credentials['SecretAccessKey'] == SECRET_ACCESS_KEY_VAL
assert credentials['Token'] == SESSION_TOKEN_VAL
def test_get_aws_security_credentials_instance_metadata_role_name_bytes(mocker):
mocker.patch.dict(os.environ, {})
mocker.patch('os.path.exists', return_value=False)
response = json.dumps({
'Code': 'Success',
'LastUpdated': '2019-10-25T14:41:42Z',
'Type': 'AWS-HMAC',
'AccessKeyId': ACCESS_KEY_ID_VAL,
'SecretAccessKey': SECRET_ACCESS_KEY_VAL,
'Token': SESSION_TOKEN_VAL,
'Expiration': '2019-10-25T21:17:24Z'
})
side_effects = [MockUrlLibResponse(data=b'FAKE_IAM_ROLE_NAME'), MockUrlLibResponse(data=response)]
mocker.patch('watchdog.urlopen', side_effect=side_effects)
credentials = watchdog.get_aws_security_credentials('metadata:') credentials = watchdog.get_aws_security_credentials('metadata:')
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment