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
pull/5989/head
Will Thames 11 years ago committed by willthames
parent 372ae072fd
commit b9a7352e0a

@ -14,33 +14,44 @@ AWS_REGIONS = ['ap-northeast-1',
'us-west-2'] 'us-west-2']
def ec2_argument_keys_spec(): def aws_common_argument_spec():
return dict( return dict(
ec2_url=dict(),
aws_secret_key=dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True), aws_secret_key=dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True),
aws_access_key=dict(aliases=['ec2_access_key', 'access_key']), 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(): def ec2_argument_spec():
spec = ec2_argument_keys_spec() spec = aws_common_argument_spec()
spec.update( spec.update(
dict( dict(
region=dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS), region=dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS),
validate_certs=dict(default=True, type='bool'),
ec2_url=dict(),
) )
) )
return spec 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 # Check module args for credentials, then check environment vars
# access_key
ec2_url = module.params.get('ec2_url') ec2_url = module.params.get('ec2_url')
ec2_secret_key = module.params.get('aws_secret_key') access_key = module.params.get('aws_access_key')
ec2_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') region = module.params.get('region')
profile_name = module.params.get('profile')
validate_certs = module.params.get('validate_certs')
if not ec2_url: if not ec2_url:
if 'EC2_URL' in os.environ: if 'EC2_URL' in os.environ:
@ -48,21 +59,27 @@ def get_ec2_creds(module):
elif 'AWS_URL' in os.environ: elif 'AWS_URL' in os.environ:
ec2_url = os.environ['AWS_URL'] ec2_url = os.environ['AWS_URL']
if not ec2_access_key: if not access_key:
if 'EC2_ACCESS_KEY' in os.environ: 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: 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: 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: 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: 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: 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 not region:
if 'EC2_REGION' in os.environ: if 'EC2_REGION' in os.environ:
@ -71,39 +88,75 @@ def get_ec2_creds(module):
region = os.environ['AWS_REGION'] region = os.environ['AWS_REGION']
else: else:
# boto.config.get returns None if config not found # 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: if not region:
region = boto.config.get('Boto', 'ec2_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): def ec2_connect(module):
""" Return an ec2 connection""" """ Return an ec2 connection"""
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module) region, ec2_url, boto_params = get_aws_connection_info(module)
validate_certs = module.params.get('validate_certs', True)
# If we have a region specified, connect to its endpoint. # If we have a region specified, connect to its endpoint.
if region: if region:
try: try:
if HAS_LOOSE_VERSION and LooseVersion(boto.Version) >= LooseVersion("2.6.0"): ec2 = connect_to_aws(boto.ec2, region, **boto_params)
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)
except boto.exception.NoAuthHandlerFound, e: 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 # Otherwise, no region so we fallback to the old connection method
elif ec2_url: elif ec2_url:
try: try:
if HAS_LOOSE_VERSION and LooseVersion(boto.Version) >= LooseVersion("2.6.0"): ec2 = boto.connect_ec2_endpoint(ec2_url, **boto_params)
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)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg=str(e))
else: else:
module.fail_json(msg="Either region or ec2_url must be specified") module.fail_json(msg="Either region or ec2_url must be specified")
return ec2
return ec2

@ -220,6 +220,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Seth Vidal, Tim Gerla, Lester Wade author: Seth Vidal, Tim Gerla, Lester Wade

@ -109,6 +109,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Evan Duffield <eduffield@iacquire.com> author: Evan Duffield <eduffield@iacquire.com>

@ -61,6 +61,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Lorin Hochstein <lorin@nimbisservices.com> author: Lorin Hochstein <lorin@nimbisservices.com>

@ -65,6 +65,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
''' '''

@ -56,6 +56,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Vincent Viallet author: Vincent Viallet

@ -70,6 +70,21 @@ options:
required: false required: false
default: null default: null
aliases: [] 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" ] requirements: [ "boto" ]
author: Will Thames author: Will Thames
''' '''

@ -67,6 +67,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Lester Wade author: Lester Wade

@ -90,6 +90,20 @@ options:
choices: ["yes", "no"] choices: ["yes", "no"]
aliases: [] aliases: []
version_added: "1.5" 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" ] requirements: [ "boto" ]
author: Lester Wade author: Lester Wade

Loading…
Cancel
Save