Commit 19807fdf authored by Yuan Gao's avatar Yuan Gao
Browse files

Enable region sourcing from efs-utils configuration file and fix stunnel exec...

Enable region sourcing from efs-utils configuration file and fix stunnel exec path issue in openSUSE
parent 8766cf14
......@@ -11,7 +11,7 @@ set -ex
BASE_DIR=$(pwd)
BUILD_ROOT=${BASE_DIR}/build/debbuild
VERSION=1.23
VERSION=1.24
echo 'Cleaning deb build workspace'
rm -rf ${BUILD_ROOT}
......
......@@ -7,5 +7,5 @@
#
[global]
version=1.23
release=2
version=1.24
release=1
Package: amazon-efs-utils
Architecture: all
Version: 1.23
Version: 1.24
Section: utils
Depends: python|python2, nfs-common, stunnel4 (>= 4.56), openssl (>= 1.0.2), util-linux
Priority: optional
......
......@@ -20,8 +20,8 @@
%endif
Name : amazon-efs-utils
Version : 1.23
Release : 2%{?dist}
Version : 1.24
Release : 1%{?dist}
Summary : This package provides utilities for simplifying the use of EFS file systems
Group : Amazon/Tools
......@@ -119,6 +119,10 @@ fi
%clean
%changelog
* Tue Mar 10 2020 Yuan Gao <ygaochn@amazon.com> - 1.24-1
- Enable efs-utils to source region from config file for sigv4 auth
- Fix the issue that stunnel bin exec cannot be found in certain linux distributions
* Tue Mar 02 2020 Yuan Gao <ygaochn@amazon.com> - 1.23-2
- Support new option: netns, enable file system to mount in given network namespace
- Support new option: awscredsuri, enable sourcing iam authorization from aws credentials relative uri
......
......@@ -16,6 +16,8 @@ state_file_dir_mode = 750
[mount]
dns_name_format = {fs_id}.efs.{region}.{dns_name_suffix}
dns_name_suffix = amazonaws.com
#The region of the file system when mounting from on-premises or cross region.
#region = us-east-1
stunnel_debug_enabled = false
stunnel_cafile = /etc/amazon/efs/efs-utils.crt
......
......@@ -69,11 +69,13 @@ except ImportError:
from urllib.error import URLError, HTTPError
VERSION = '1.23'
VERSION = '1.24'
SERVICE = 'elasticfilesystem'
CONFIG_FILE = '/etc/amazon/efs/efs-utils.conf'
CONFIG_SECTION = 'mount'
CLIENT_INFO_SECTION = 'client-info'
CLIENT_SOURCE_STR_LEN_LIMIT = 100
LOG_DIR = '/var/log/amazon/efs'
LOG_FILE = 'mount.log'
......@@ -117,6 +119,8 @@ CN = %s
%s
%s
%s
"""
......@@ -205,31 +209,67 @@ def fatal_error(user_message, log_message=None, exit_code=1):
sys.exit(exit_code)
def get_region():
"""Return this instance's region via the instance metadata service."""
def get_target_region(config):
def _fatal_error(message):
fatal_error('Error retrieving region', message)
fatal_error('Error retrieving region. Please set the "region" parameter in the efs-utils configuration file.', message)
metadata_exception = 'Unknown error'
try:
return config.get(CONFIG_SECTION, 'region')
except NoOptionError:
pass
try:
return get_region_from_instance_metadata()
except Exception as e:
metadata_exception = e
logging.warn('Region not found in config file and metadata service call failed, falling back '
'to legacy "dns_name_format" check')
try:
region = get_region_from_legacy_dns_format(config)
sys.stdout.write('Warning: region obtained from "dns_name_format" field. Please set the "region" '
'parameter in the efs-utils configuration file.')
return region
except Exception:
logging.warn('Legacy check for region in "dns_name_format" failed')
_fatal_error(metadata_exception)
def get_region_from_instance_metadata():
err_msg = None
try:
token = get_aws_ec2_metadata_token()
headers = {}
if token:
headers = {'X-aws-ec2-metadata-token': token}
instance_identity = get_aws_ec2_metadata(headers)
return instance_identity['region']
except HTTPError as e:
_fatal_error('Unable to reach instance metadata service at %s: status=%d'
% (INSTANCE_METADATA_SERVICE_URL, e.code))
except URLError as e:
_fatal_error('Unable to reach the instance metadata service at %s. If this is an on-premises instance, replace '
'"{region}" in the "dns_name_format" option in %s with the region of the EFS file system you are mounting.\n'
'See %s for more detail. %s'
% (INSTANCE_METADATA_SERVICE_URL, CONFIG_FILE, 'https://docs.aws.amazon.com/console/efs/direct-connect', e))
except (HTTPError, URLError) as e:
err_msg = 'Unable to reach instance metadata service at %s: status=%d' % (INSTANCE_METADATA_SERVICE_URL, e.code)
except ValueError as e:
_fatal_error('Error parsing json: %s' % (e,))
err_msg = 'Error parsing json: %s' % (e,)
except KeyError as e:
_fatal_error('Region not present in %s: %s' % (instance_identity, e))
err_msg = 'Region not present in %s: %s' % (instance_identity, e)
if err_msg:
raise Exception(err_msg)
def get_region_from_legacy_dns_format(config):
"""
For backwards compatibility check dns_name_format to obtain the target region. This functionality
should only be used if region is not present in the config file and metadata calls fail.
"""
dns_name_format = config.get(CONFIG_SECTION, 'dns_name_format')
if '{region}' not in dns_name_format:
split_dns_name_format = dns_name_format.split('.')
if '{dns_name_suffix}' in dns_name_format:
return split_dns_name_format[-2]
elif 'amazonaws.com' in dns_name_format:
return split_dns_name_format[-3]
raise Exception('Region not found in dns_name_format')
def get_aws_ec2_metadata_token():
......@@ -258,14 +298,6 @@ def get_aws_ec2_metadata(headers):
return instance_identity
def get_region_helper(config):
dns_name_format = config.get(CONFIG_SECTION, 'dns_name_format')
if '{region}' in dns_name_format:
return get_region()
else:
return dns_name_format.split('.')[-3]
def get_aws_security_credentials(use_iam, awsprofile=None, aws_creds_uri=None):
"""
Lookup AWS security credentials (access key ID and secret access key). Adapted credentials provider chain from:
......@@ -547,19 +579,36 @@ def is_stunnel_option_supported(stunnel_output, stunnel_option_name):
return supported
def get_version_specific_stunnel_options(config):
proc = subprocess.Popen(['stunnel', '-help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
def get_version_specific_stunnel_options():
stunnel_command = [_stunnel_bin(), '-help']
proc = subprocess.Popen(stunnel_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
proc.wait()
_, err = proc.communicate()
stunnel_output = err.splitlines()
check_host_supported = is_stunnel_option_supported(stunnel_output, 'checkHost')
ocsp_aia_supported = is_stunnel_option_supported(stunnel_output, 'OCSPaia')
check_host_supported = is_stunnel_option_supported(stunnel_output, b'checkHost')
ocsp_aia_supported = is_stunnel_option_supported(stunnel_output, b'OCSPaia')
return check_host_supported, ocsp_aia_supported
def _stunnel_bin():
return find_command_path('stunnel',
'Please install it following the instructions at '
'https://docs.aws.amazon.com/efs/latest/ug/using-amazon-efs-utils.html#upgrading-stunnel')
def find_command_path(command, install_method):
try:
env_path = '/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin'
os.putenv('PATH', env_path)
path = subprocess.check_output(['which', command])
except subprocess.CalledProcessError as e:
fatal_error('Failed to locate %s in %s - %s' % (command, env_path, install_method), e)
return path.strip().decode()
def get_system_release_version():
system_release_version = 'unknown'
try:
......@@ -596,7 +645,7 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por
efs_config['cert'] = cert_details['certificate']
efs_config['key'] = cert_details['privateKey']
check_host_supported, ocsp_aia_supported = get_version_specific_stunnel_options(config)
check_host_supported, ocsp_aia_supported = get_version_specific_stunnel_options()
tls_controls_message = 'WARNING: Your client lacks sufficient controls to properly enforce TLS. Please upgrade stunnel, ' \
'or disable "%%s" in %s.\nSee %s for more detail.' % (CONFIG_FILE,
......@@ -769,7 +818,7 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta
cert_details['mountStateDir'] = get_mount_specific_filename(fs_id, mountpoint, tls_port) + '+'
# common name for certificate signing request is max 64 characters
cert_details['commonName'] = socket.gethostname()[0:64]
cert_details['region'] = get_region_helper(config)
cert_details['region'] = get_target_region(config)
cert_details['certificateCreationTime'] = create_certificate(config, cert_details['mountStateDir'],
cert_details['commonName'], cert_details['region'], fs_id,
security_credentials, ap_id=ap_id, base_path=state_file_dir)
......@@ -793,14 +842,14 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta
stunnel_config_file = write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level,
ocsp_enabled, options, cert_details=cert_details)
tunnel_args = ['stunnel', stunnel_config_file]
tunnel_args = [_stunnel_bin(), stunnel_config_file]
if 'netns' in options:
tunnel_args = ['nsenter', '--net=' + options['netns']] + tunnel_args
# launch the tunnel in a process group so if it has any child processes, they can be killed easily by the mount watchdog
logging.info('Starting TLS tunnel: "%s"', ' '.join(tunnel_args))
tunnel_proc = subprocess.Popen(
tunnel_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid, close_fds=True)
tunnel_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid, close_fds=True)
logging.info('Started TLS tunnel, pid: %d', tunnel_proc.pid)
temp_tls_state_file = write_tls_tunnel_state_file(fs_id, mountpoint, tls_port, tunnel_proc.pid, tunnel_args,
......@@ -909,6 +958,18 @@ def parse_arguments(config, args=None):
return fs_id, path, mountpoint, options
def get_client_info(config):
client_info = {}
# source key/value pair in config file
if config.has_option(CLIENT_INFO_SECTION, 'source'):
client_source = config.get(CLIENT_INFO_SECTION, 'source')
if 0 < len(client_source) <= CLIENT_SOURCE_STR_LEN_LIMIT:
client_info['source'] = client_source
return client_info
def create_certificate(config, mount_name, common_name, region, fs_id, security_credentials, ap_id, base_path=STATE_FILE_DIR):
current_time = get_utc_now()
tls_paths = tls_paths_dictionary(mount_name, base_path)
......@@ -926,8 +987,9 @@ def create_certificate(config, mount_name, common_name, region, fs_id, security_
public_key = os.path.join(tls_paths['mount_dir'], 'publicKey.pem')
create_public_key(private_key, public_key)
client_info = get_client_info(config)
create_ca_conf(certificate_config, common_name, tls_paths['mount_dir'], private_key, current_time, region, fs_id,
security_credentials, ap_id)
security_credentials, ap_id, client_info)
create_certificate_signing_request(certificate_config, private_key, certificate_signing_request)
not_before = get_certificate_timestamp(current_time, minutes=-NOT_BEFORE_MINS)
......@@ -992,14 +1054,17 @@ def create_certificate_signing_request(config_path, private_key, csr_path):
subprocess_call(cmd, 'Failed to create certificate signing request (csr)')
def create_ca_conf(config_path, common_name, directory, private_key, date, region, fs_id, security_credentials, ap_id):
def create_ca_conf(config_path, common_name, directory, private_key, date,
region, fs_id, security_credentials, ap_id, client_info):
"""Populate ca/req configuration file with fresh configurations at every mount since SigV4 signature can change"""
public_key_path = os.path.join(directory, 'publicKey.pem')
ca_extension_body = ca_extension_builder(ap_id, security_credentials, fs_id) if security_credentials or ap_id else ''
ca_extension_body = ca_extension_builder(ap_id, security_credentials, fs_id, client_info)
efs_client_auth_body = efs_client_auth_builder(public_key_path, security_credentials['AccessKeyId'],
security_credentials['SecretAccessKey'], date, region, fs_id,
security_credentials['Token']) if security_credentials else ''
full_config_body = CA_CONFIG_BODY % (directory, private_key, common_name, ca_extension_body, efs_client_auth_body)
efs_client_info_body = efs_client_info_builder(client_info) if client_info else ''
full_config_body = CA_CONFIG_BODY % (directory, private_key, common_name, ca_extension_body,
efs_client_auth_body, efs_client_info_body)
with open(config_path, 'w') as f:
f.write(full_config_body)
......@@ -1007,7 +1072,7 @@ def create_ca_conf(config_path, common_name, directory, private_key, date, regio
return full_config_body
def ca_extension_builder(ap_id, security_credentials, fs_id):
def ca_extension_builder(ap_id, security_credentials, fs_id, client_info):
ca_extension_str = '[ v3_ca ]\nsubjectKeyIdentifier = hash'
if ap_id:
ca_extension_str += '\n1.3.6.1.4.1.4843.7.1 = ASN1:UTF8String:' + ap_id
......@@ -1016,6 +1081,9 @@ def ca_extension_builder(ap_id, security_credentials, fs_id):
ca_extension_str += '\n1.3.6.1.4.1.4843.7.3 = ASN1:UTF8String:' + fs_id
if client_info:
ca_extension_str += '\n1.3.6.1.4.1.4843.7.4 = ASN1:SEQUENCE:efs_client_info'
return ca_extension_str
......@@ -1035,6 +1103,13 @@ def efs_client_auth_builder(public_key_path, access_key_id, secret_access_key, d
return efs_client_auth_str
def efs_client_info_builder(client_info):
efs_client_info_str = '[ efs_client_info ]'
for key, value in client_info.items():
efs_client_info_str += '\n%s = UTF8String: %s' % (key, value)
return efs_client_info_str
def create_public_key(private_key, public_key):
cmd = 'openssl rsa -in %s -outform PEM -pubout -out %s' % (private_key, public_key)
subprocess_call(cmd, 'Failed to create public key')
......@@ -1149,7 +1224,7 @@ def get_dns_name(config, fs_id):
if '{region}' in dns_name_format:
expected_replacement_field_ct += 1
format_args['region'] = get_region()
format_args['region'] = get_target_region(config)
if '{dns_name_suffix}' in dns_name_format:
expected_replacement_field_ct += 1
......
......@@ -45,11 +45,13 @@ except ImportError:
from urllib.error import URLError
from urllib.request import urlopen
VERSION = '1.23'
VERSION = '1.24'
SERVICE = 'elasticfilesystem'
CONFIG_FILE = '/etc/amazon/efs/efs-utils.conf'
CONFIG_SECTION = 'mount-watchdog'
CLIENT_INFO_SECTION = 'client-info'
CLIENT_SOURCE_STR_LEN_LIMIT = 100
LOG_DIR = '/var/log/amazon/efs'
LOG_FILE = 'mount-watchdog.log'
......@@ -98,6 +100,8 @@ CN = %s
%s
%s
%s
"""
......@@ -565,6 +569,18 @@ def create_required_directory(config, directory):
raise
def get_client_info(config):
client_info = {}
# source key/value pair in config file
if config.has_option(CLIENT_INFO_SECTION, 'source'):
client_source = config.get(CLIENT_INFO_SECTION, 'source')
if 0 < len(client_source) <= CLIENT_SOURCE_STR_LEN_LIMIT:
client_info['source'] = client_source
return client_info
def recreate_certificate(config, mount_name, common_name, fs_id, credentials_source, ap_id, region,
base_path=STATE_FILE_DIR):
current_time = get_utc_now()
......@@ -583,8 +599,9 @@ def recreate_certificate(config, mount_name, common_name, fs_id, credentials_sou
public_key = os.path.join(tls_paths['mount_dir'], 'publicKey.pem')
create_public_key(private_key, public_key)
client_info = get_client_info(config)
config_body = create_ca_conf(certificate_config, common_name, tls_paths['mount_dir'], private_key, current_time, region,
fs_id, credentials_source, ap_id=ap_id)
fs_id, credentials_source, ap_id=ap_id, client_info=client_info)
if not config_body:
logging.error('Cannot recreate self-signed certificate')
......@@ -657,7 +674,7 @@ def create_certificate_signing_request(config_path, key_path, csr_path):
def create_ca_conf(config_path, common_name, directory, private_key, date, region, fs_id, credentials_source,
ap_id=None):
ap_id=None, client_info=None):
"""Populate ca/req configuration file with fresh configurations at every mount since SigV4 signature can change"""
public_key_path = os.path.join(directory, 'publicKey.pem')
security_credentials = get_aws_security_credentials(credentials_source) if credentials_source else ''
......@@ -666,16 +683,16 @@ def create_ca_conf(config_path, common_name, directory, private_key, date, regio
logging.error('Failed to retrieve AWS security credentials using lookup method: %s', credentials_source)
return None
ca_extension_body = ca_extension_builder(ap_id, security_credentials, fs_id)
ca_extension_body = ca_extension_builder(ap_id, security_credentials, fs_id, client_info)
efs_client_auth_body = efs_client_auth_builder(public_key_path, security_credentials['AccessKeyId'],
security_credentials['SecretAccessKey'], date, region, fs_id,
security_credentials['Token']) if credentials_source else ''
if credentials_source and not efs_client_auth_body:
logging.error('Failed to create AWS SigV4 signature section for OpenSSL config. Public Key path: %s', public_key_path)
return None
full_config_body = CA_CONFIG_BODY % (directory, private_key, common_name, ca_extension_body, efs_client_auth_body)
efs_client_info_body = efs_client_info_builder(client_info) if client_info else ''
full_config_body = CA_CONFIG_BODY % (directory, private_key, common_name, ca_extension_body,
efs_client_auth_body, efs_client_info_body)
with open(config_path, 'w') as f:
f.write(full_config_body)
......@@ -683,7 +700,7 @@ def create_ca_conf(config_path, common_name, directory, private_key, date, regio
return full_config_body
def ca_extension_builder(ap_id, security_credentials, fs_id):
def ca_extension_builder(ap_id, security_credentials, fs_id, client_info):
ca_extension_str = '[ v3_ca ]\nsubjectKeyIdentifier = hash'
if ap_id:
ca_extension_str += '\n1.3.6.1.4.1.4843.7.1 = ASN1:UTF8String:' + ap_id
......@@ -691,6 +708,8 @@ def ca_extension_builder(ap_id, security_credentials, fs_id):
ca_extension_str += '\n1.3.6.1.4.1.4843.7.2 = ASN1:SEQUENCE:efs_client_auth'
ca_extension_str += '\n1.3.6.1.4.1.4843.7.3 = ASN1:UTF8String:' + fs_id
if client_info:
ca_extension_str += '\n1.3.6.1.4.1.4843.7.4 = ASN1:SEQUENCE:efs_client_info'
return ca_extension_str
......@@ -715,6 +734,13 @@ def efs_client_auth_builder(public_key_path, access_key_id, secret_access_key, d
return efs_client_auth_str
def efs_client_info_builder(client_info):
efs_client_info_str = '[ efs_client_info ]'
for key, value in client_info.items():
efs_client_info_str += '\n%s = UTF8String: %s' % (key, value)
return efs_client_info_str
def create_public_key(private_key, public_key):
cmd = 'openssl rsa -in %s -outform PEM -pubout -out %s' % (private_key, public_key)
subprocess_call(cmd, 'Failed to create public key')
......
......@@ -14,6 +14,7 @@ from mock import MagicMock
AP_ID = 'fsap-beefdead'
FS_ID = 'fs-deadbeef'
CLIENT_SOURCE = 'test'
DNS_NAME = '%s.efs.us-east-1.amazonaws.com' % FS_ID
MOUNT_POINT = '/mnt'
REGION = 'us-east-1'
......@@ -33,7 +34,7 @@ def setup_mocks(mocker):
mocker.patch('mount_efs.get_tls_port_range', return_value=(DEFAULT_TLS_PORT, DEFAULT_TLS_PORT + 10))
mocker.patch('socket.socket', return_value=MagicMock())
mocker.patch('mount_efs.get_dns_name', return_value=DNS_NAME)
mocker.patch('mount_efs.get_region_helper', return_value=REGION)
mocker.patch('mount_efs.get_target_region', return_value=REGION)
mocker.patch('mount_efs.write_tls_tunnel_state_file', return_value='~mocktempfile')
mocker.patch('mount_efs.create_certificate')
mocker.patch('os.rename')
......@@ -64,13 +65,14 @@ def test_bootstrap_tls_state_file_dir_exists(mocker, tmpdir):
popen_mock, _ = setup_mocks(mocker)
state_file_dir = str(tmpdir)
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {}, state_file_dir):
pass
args, _ = popen_mock.call_args
args = args[0]
assert 'stunnel' in args
assert '/usr/bin/stunnel' in args
assert EXPECTED_STUNNEL_CONFIG_FILE in args
......@@ -90,6 +92,7 @@ def test_bootstrap_tls_state_file_nonexistent_dir(mocker, tmpdir):
assert not os.path.exists(state_file_dir)
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {}, state_file_dir):
pass
......@@ -115,6 +118,7 @@ def test_bootstrap_tls_no_cert_creation(mocker, tmpdir):
MOCK_CONFIG.get.side_effect = config_get_side_effect
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
try:
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {}, state_file_dir):
pass
......@@ -130,7 +134,7 @@ def test_bootstrap_tls_no_cert_creation(mocker, tmpdir):
def test_bootstrap_tls_cert_created(mocker, tmpdir):
setup_mocks_without_popen(mocker)
mocker.patch('mount_efs.get_mount_specific_filename', return_value=DNS_NAME)
mocker.patch('mount_efs.get_region_helper', return_value=REGION)
mocker.patch('mount_efs.get_target_region', return_value=REGION)
state_file_dir = str(tmpdir)
tls_dict = mount_efs.tls_paths_dictionary(DNS_NAME + '+', state_file_dir)
......@@ -142,14 +146,17 @@ def test_bootstrap_tls_cert_created(mocker, tmpdir):
return '0755'
elif section == mount_efs.CONFIG_SECTION and field == 'dns_name_format':
return '{fs_id}.efs.{region}.amazonaws.com'
elif section == mount_efs.CLIENT_INFO_SECTION and field == 'source':
return CLIENT_SOURCE
else:
raise ValueError('Unexpected arguments')
MOCK_CONFIG.get.side_effect = config_get_side_effect
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
try:
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {'accesspoint': AP_ID},
state_file_dir):
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID,
MOUNT_POINT, {'accesspoint': AP_ID}, state_file_dir):
pass
except OSError as e:
assert '[Errno 2] No such file or directory' in str(e)
......@@ -166,6 +173,7 @@ def test_bootstrap_tls_non_default_port(mocker, tmpdir):
state_file_dir = str(tmpdir)
tls_port = 1000
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {'tlsport': tls_port},
state_file_dir):
pass
......@@ -174,7 +182,7 @@ def test_bootstrap_tls_non_default_port(mocker, tmpdir):
popen_args = popen_args[0]
write_config_args, _ = write_config_mock.call_args
assert 'stunnel' in popen_args
assert '/usr/bin/stunnel' in popen_args
assert EXPECTED_STUNNEL_CONFIG_FILE in popen_args
assert 1000 == write_config_args[4] # positional argument for tls_port
......@@ -184,6 +192,7 @@ def test_bootstrap_tls_non_default_verify_level(mocker, tmpdir):
state_file_dir = str(tmpdir)
verify = 0
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {'verify': verify},
state_file_dir):
pass
......@@ -192,7 +201,7 @@ def test_bootstrap_tls_non_default_verify_level(mocker, tmpdir):
popen_args = popen_args[0]
write_config_args, _ = write_config_mock.call_args
assert 'stunnel' in popen_args
assert '/usr/bin/stunnel' in popen_args
assert EXPECTED_STUNNEL_CONFIG_FILE in popen_args
assert 0 == write_config_args[6] # positional argument for verify_level
......@@ -201,6 +210,7 @@ def test_bootstrap_tls_ocsp_option(mocker, tmpdir):
popen_mock, write_config_mock = setup_mocks(mocker)
state_file_dir = str(tmpdir)
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {'ocsp': None}, state_file_dir):
pass
......@@ -208,7 +218,7 @@ def test_bootstrap_tls_ocsp_option(mocker, tmpdir):
popen_args = popen_args[0]
write_config_args, _ = write_config_mock.call_args
assert 'stunnel' in popen_args
assert '/usr/bin/stunnel' in popen_args
assert EXPECTED_STUNNEL_CONFIG_FILE in popen_args
# positional argument for ocsp_override
assert write_config_args[7] is True
......@@ -218,6 +228,7 @@ def test_bootstrap_tls_noocsp_option(mocker, tmpdir):
popen_mock, write_config_mock = setup_mocks(mocker)
state_file_dir = str(tmpdir)
mocker.patch('mount_efs._stunnel_bin', return_value='/usr/bin/stunnel')
with mount_efs.bootstrap_tls(MOCK_CONFIG, INIT_SYSTEM, DNS_NAME, FS_ID, MOUNT_POINT, {'noocsp': None}, state_file_dir):
pass
......@@ -225,7 +236,7 @@ def test_bootstrap_tls_noocsp_option(mocker, tmpdir):
popen_args = popen_args[0]
write_config_args, _ = write_config_mock.call_args
assert 'stunnel' in popen_args
assert '/usr/bin/stunnel' in popen_args
assert EXPECTED_STUNNEL_CONFIG_FILE in popen_args
# positional argument for ocsp_override
assert write_config_args[7] is False
......@@ -21,6 +21,7 @@ except ImportError:
FS_ID = 'fs-deadbeef'
AP_ID = 'fsap-fedcba9876543210'
CLIENT_INFO = {'source': 'test'}
REGION = 'us-east-1'
COMMON_NAME = 'fs-deadbeef.efs.us-east-1.amazonaws.com'
MOUNT_NAME = 'fs-deadbeef.mount.dir.12345'
......@@ -44,8 +45,8 @@ PUBLIC_KEY_BODY = '-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AM
@pytest.fixture(autouse=True)
def setup_method(mocker):
mocker.patch('mount_efs.get_region', return_value=REGION)
mocker.patch('mount_efs.get_region_helper', return_value=REGION)
mocker.patch('mount_efs.get_region_from_instance_metadata', return_value=REGION)
mocker.patch('mount_efs.get_target_region', return_value=REGION)
mocker.patch('mount_efs.get_aws_security_credentials', return_value=CREDENTIALS)
mocker.patch('mount_efs.get_utc_now', return_value=FIXED_DT)
mocker.patch('socket.gethostbyname')
......@@ -62,7 +63,7 @@ def _get_config():