From b9a7352e0a8e2cd8a72e29a7cc9a800bc83155c8 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Wed, 5 Feb 2014 21:11:06 +1000 Subject: [PATCH 1/2] Work to allow security tokens and profiles to work with Ansible Allow security tokens and profiles to be used as arguments to the 'common' ec2 modules Mostly refactoring to provide two new methods, `get_aws_connection_info`, which results in a dict that can be passed through to the boto `connect_to_region` calls, and `connect_to_aws` that can pass that dict through to the `connect_to_region` method of the appropriate module. Tidied up some variable names Works around boto/boto#2100 profiles don't work with boto < 2.24, but this detects for that and fails with an appropriate message. It is designed to work if profile is not passed but boto < 2.24 is installed. Modifications to allow empty aws auth variables to be passed (this is useful if wanting to have the keys as an optional parameter in ec2 calls - if set, use this value, if not set, use boto config or env variables) Reworked validate_certs improvements to work with refactoring Added documentation for profile and security_token to affected modules --- lib/ansible/module_utils/ec2.py | 113 +++++++++++++++++++++++--------- library/cloud/ec2 | 14 ++++ library/cloud/ec2_ami | 14 ++++ library/cloud/ec2_eip | 14 ++++ library/cloud/ec2_group | 14 ++++ library/cloud/ec2_key | 14 ++++ library/cloud/ec2_snapshot | 19 +++++- library/cloud/ec2_tag | 14 ++++ library/cloud/ec2_vol | 14 ++++ 9 files changed, 198 insertions(+), 32 deletions(-) diff --git a/lib/ansible/module_utils/ec2.py b/lib/ansible/module_utils/ec2.py index 9156df766b..ab6c1d27e9 100644 --- a/lib/ansible/module_utils/ec2.py +++ b/lib/ansible/module_utils/ec2.py @@ -14,33 +14,44 @@ AWS_REGIONS = ['ap-northeast-1', 'us-west-2'] -def ec2_argument_keys_spec(): +def aws_common_argument_spec(): return dict( + ec2_url=dict(), aws_secret_key=dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True), aws_access_key=dict(aliases=['ec2_access_key', 'access_key']), + validate_certs=dict(default=True, type='bool'), + security_token=dict(no_log=True), + profile=dict(), ) + return spec def ec2_argument_spec(): - spec = ec2_argument_keys_spec() + spec = aws_common_argument_spec() spec.update( dict( region=dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS), - validate_certs=dict(default=True, type='bool'), - ec2_url=dict(), ) ) return spec -def get_ec2_creds(module): +def boto_supports_profile_name(): + return hasattr(boto.ec2.EC2Connection, 'profile_name') + + +def get_aws_connection_info(module): # Check module args for credentials, then check environment vars + # access_key ec2_url = module.params.get('ec2_url') - ec2_secret_key = module.params.get('aws_secret_key') - ec2_access_key = module.params.get('aws_access_key') + access_key = module.params.get('aws_access_key') + secret_key = module.params.get('aws_secret_key') + security_token = module.params.get('security_token') region = module.params.get('region') + profile_name = module.params.get('profile') + validate_certs = module.params.get('validate_certs') if not ec2_url: if 'EC2_URL' in os.environ: @@ -48,21 +59,27 @@ def get_ec2_creds(module): elif 'AWS_URL' in os.environ: ec2_url = os.environ['AWS_URL'] - if not ec2_access_key: + if not access_key: if 'EC2_ACCESS_KEY' in os.environ: - ec2_access_key = os.environ['EC2_ACCESS_KEY'] + access_key = os.environ['EC2_ACCESS_KEY'] elif 'AWS_ACCESS_KEY_ID' in os.environ: - ec2_access_key = os.environ['AWS_ACCESS_KEY_ID'] + access_key = os.environ['AWS_ACCESS_KEY_ID'] elif 'AWS_ACCESS_KEY' in os.environ: - ec2_access_key = os.environ['AWS_ACCESS_KEY'] + access_key = os.environ['AWS_ACCESS_KEY'] + else: + # in case access_key came in as empty string + access_key = None - if not ec2_secret_key: + if not secret_key: if 'EC2_SECRET_KEY' in os.environ: - ec2_secret_key = os.environ['EC2_SECRET_KEY'] + secret_key = os.environ['EC2_SECRET_KEY'] elif 'AWS_SECRET_ACCESS_KEY' in os.environ: - ec2_secret_key = os.environ['AWS_SECRET_ACCESS_KEY'] + secret_key = os.environ['AWS_SECRET_ACCESS_KEY'] elif 'AWS_SECRET_KEY' in os.environ: - ec2_secret_key = os.environ['AWS_SECRET_KEY'] + secret_key = os.environ['AWS_SECRET_KEY'] + else: + # in case secret_key came in as empty string + secret_key = None if not region: if 'EC2_REGION' in os.environ: @@ -71,39 +88,75 @@ def get_ec2_creds(module): region = os.environ['AWS_REGION'] else: # boto.config.get returns None if config not found - region = boto.config.get('Boto', 'aws_region') + region = boto.config.get('Boto', 'aws_region') if not region: region = boto.config.get('Boto', 'ec2_region') - return ec2_url, ec2_access_key, ec2_secret_key, region + if not security_token: + if 'AWS_SECURITY_TOKEN' in os.environ: + security_token = os.environ['AWS_SECURITY_TOKEN'] + else: + # in case security_token came in as empty string + security_token = None + + boto_params = dict(aws_access_key_id=access_key, + aws_secret_access_key=secret_key, + security_token=security_token) + + # profile_name only works as a key in boto >= 2.24 + # so only set profile_name if passed as an argument + if profile_name: + if not boto_supports_profile_name(): + module.fail_json("boto does not support profile_name before 2.24") + boto_params['profile_name'] = profile_name + + if validate_certs and HAS_LOOSE_VERSION and LooseVersion(boto.Version) >= LooseVersion("2.6.0"): + boto_params['validate_certs'] = validate_certs + + return region, ec2_url, boto_params + + +def get_ec2_creds(module): + ''' for compatibility mode with old modules that don't/can't yet + use ec2_connect method ''' + region, ec2_url, boto_params = get_aws_connection_info(module) + return ec2_url, boto_params['aws_access_key_id'], boto_params['aws_secret_access_key'], region + + +def boto_fix_security_token_in_profile(conn, profile_name): + ''' monkey patch for boto issue boto/boto#2100 ''' + profile = 'profile ' + profile_name + if boto.config.has_option(profile, 'aws_security_token'): + conn.provider.set_security_token(boto.config.get(profile, 'aws_security_token')) + return conn + + +def connect_to_aws(aws_module, region, **params): + conn = aws_module.connect_to_region(region, **params) + if params.get('profile_name'): + conn = boto_fix_security_token_in_profile(conn, params['profile_name']) + return conn def ec2_connect(module): """ Return an ec2 connection""" - ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module) - validate_certs = module.params.get('validate_certs', True) + region, ec2_url, boto_params = get_aws_connection_info(module) # If we have a region specified, connect to its endpoint. if region: try: - if HAS_LOOSE_VERSION and LooseVersion(boto.Version) >= LooseVersion("2.6.0"): - ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key, validate_certs=validate_certs) - else: - ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key) + ec2 = connect_to_aws(boto.ec2, region, **boto_params) except boto.exception.NoAuthHandlerFound, e: - module.fail_json(msg = str(e)) + module.fail_json(msg=str(e)) # Otherwise, no region so we fallback to the old connection method elif ec2_url: try: - if HAS_LOOSE_VERSION and LooseVersion(boto.Version) >= LooseVersion("2.6.0"): - ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key, validate_certs=validate_certs) - else: - ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key) + ec2 = boto.connect_ec2_endpoint(ec2_url, **boto_params) except boto.exception.NoAuthHandlerFound, e: - module.fail_json(msg = str(e)) + module.fail_json(msg=str(e)) else: module.fail_json(msg="Either region or ec2_url must be specified") - return ec2 + return ec2 diff --git a/library/cloud/ec2 b/library/cloud/ec2 index e050611fcf..54fc9eea46 100644 --- a/library/cloud/ec2 +++ b/library/cloud/ec2 @@ -220,6 +220,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Seth Vidal, Tim Gerla, Lester Wade diff --git a/library/cloud/ec2_ami b/library/cloud/ec2_ami index 866f2caf76..94c1e864a8 100644 --- a/library/cloud/ec2_ami +++ b/library/cloud/ec2_ami @@ -109,6 +109,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Evan Duffield diff --git a/library/cloud/ec2_eip b/library/cloud/ec2_eip index de041f4222..4d6d24eaa3 100644 --- a/library/cloud/ec2_eip +++ b/library/cloud/ec2_eip @@ -61,6 +61,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Lorin Hochstein diff --git a/library/cloud/ec2_group b/library/cloud/ec2_group index bbbb0fc24e..5d72c009ac 100644 --- a/library/cloud/ec2_group +++ b/library/cloud/ec2_group @@ -65,6 +65,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] ''' diff --git a/library/cloud/ec2_key b/library/cloud/ec2_key index 5e6950d2c8..6523c70e95 100644 --- a/library/cloud/ec2_key +++ b/library/cloud/ec2_key @@ -56,6 +56,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Vincent Viallet diff --git a/library/cloud/ec2_snapshot b/library/cloud/ec2_snapshot index b5d9df3b52..81cf3554b3 100644 --- a/library/cloud/ec2_snapshot +++ b/library/cloud/ec2_snapshot @@ -59,17 +59,32 @@ options: default: null aliases: [] instance_id: - description: + description: - instance that has a the required volume to snapshot mounted required: false default: null aliases: [] device_name: - description: + description: - device name of a mounted volume to be snapshotted required: false default: null aliases: [] + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" + requirements: [ "boto" ] author: Will Thames ''' diff --git a/library/cloud/ec2_tag b/library/cloud/ec2_tag index ca5a337646..7e3e4776d0 100644 --- a/library/cloud/ec2_tag +++ b/library/cloud/ec2_tag @@ -67,6 +67,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Lester Wade diff --git a/library/cloud/ec2_vol b/library/cloud/ec2_vol index bdd2eae382..fef476a216 100644 --- a/library/cloud/ec2_vol +++ b/library/cloud/ec2_vol @@ -90,6 +90,20 @@ options: choices: ["yes", "no"] aliases: [] version_added: "1.5" + profile: + description: + - uses a boto profile. Only works with boto >= 2.24.0 + required: false + default: null + aliases: [] + version_added: "1.5" + security_token: + description: + - security token to authenticate against AWS + required: false + default: null + aliases: [] + version_added: "1.5" requirements: [ "boto" ] author: Lester Wade From 8ca3bb413708d7cb33230ce02c05266900f6b9ea Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Tue, 11 Mar 2014 10:48:16 -0500 Subject: [PATCH 2/2] Updating profile/security_token version_added labels --- library/cloud/ec2 | 4 ++-- library/cloud/ec2_ami | 4 ++-- library/cloud/ec2_eip | 4 ++-- library/cloud/ec2_group | 4 ++-- library/cloud/ec2_key | 4 ++-- library/cloud/ec2_snapshot | 4 ++-- library/cloud/ec2_tag | 4 ++-- library/cloud/ec2_vol | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/cloud/ec2 b/library/cloud/ec2 index ba37c3cc3f..23ec3eabff 100644 --- a/library/cloud/ec2 +++ b/library/cloud/ec2 @@ -226,14 +226,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Seth Vidal, Tim Gerla, Lester Wade diff --git a/library/cloud/ec2_ami b/library/cloud/ec2_ami index 94c1e864a8..446c7417e0 100644 --- a/library/cloud/ec2_ami +++ b/library/cloud/ec2_ami @@ -115,14 +115,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Evan Duffield diff --git a/library/cloud/ec2_eip b/library/cloud/ec2_eip index 4d6d24eaa3..7eac979841 100644 --- a/library/cloud/ec2_eip +++ b/library/cloud/ec2_eip @@ -67,14 +67,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Lorin Hochstein diff --git a/library/cloud/ec2_group b/library/cloud/ec2_group index 5d72c009ac..1dd463cc8d 100644 --- a/library/cloud/ec2_group +++ b/library/cloud/ec2_group @@ -71,14 +71,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] ''' diff --git a/library/cloud/ec2_key b/library/cloud/ec2_key index 6523c70e95..289deb6c9d 100644 --- a/library/cloud/ec2_key +++ b/library/cloud/ec2_key @@ -62,14 +62,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Vincent Viallet diff --git a/library/cloud/ec2_snapshot b/library/cloud/ec2_snapshot index 81cf3554b3..e637ebefa3 100644 --- a/library/cloud/ec2_snapshot +++ b/library/cloud/ec2_snapshot @@ -76,14 +76,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Will Thames diff --git a/library/cloud/ec2_tag b/library/cloud/ec2_tag index c9de515585..92af644933 100644 --- a/library/cloud/ec2_tag +++ b/library/cloud/ec2_tag @@ -73,14 +73,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Lester Wade diff --git a/library/cloud/ec2_vol b/library/cloud/ec2_vol index fef476a216..faacc82da8 100644 --- a/library/cloud/ec2_vol +++ b/library/cloud/ec2_vol @@ -96,14 +96,14 @@ options: required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" security_token: description: - security token to authenticate against AWS required: false default: null aliases: [] - version_added: "1.5" + version_added: "1.6" requirements: [ "boto" ] author: Lester Wade