2015-02-17 21:22:40 +01:00
#!/usr/bin/python
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
DOCUMENTATION = '''
- - -
module : iam
short_description : Manage IAM users , groups , roles and keys
description :
2016-03-14 20:24:43 +01:00
- Allows for the management of IAM users , user API keys , groups , roles .
2015-02-17 21:22:40 +01:00
version_added : " 2.0 "
options :
iam_type :
description :
- Type of IAM resource
required : true
default : null
2016-03-14 20:24:43 +01:00
choices : [ " user " , " group " , " role " ]
2015-02-17 21:22:40 +01:00
name :
description :
- Name of IAM resource to create or identify
required : true
new_name :
description :
- When state is update , will replace name with new_name on IAM resource
required : false
2015-06-05 20:09:02 +02:00
default : null
2015-02-17 21:22:40 +01:00
new_path :
description :
- When state is update , will replace the path with new_path on the IAM resource
required : false
2015-06-05 20:09:02 +02:00
default : null
2015-02-17 21:22:40 +01:00
state :
description :
- Whether to create , delete or update the IAM resource . Note , roles cannot be updated .
required : true
default : null
choices : [ " present " , " absent " , " update " ]
path :
description :
- When creating or updating , specify the desired path of the resource . If state is present , it will replace the current path to match what is passed in when they do not match .
required : false
default : " / "
2016-06-08 15:23:55 +02:00
trust_policy :
description :
- The inline ( JSON or YAML ) trust policy document that grants an entity permission to assume the role . Mutually exclusive with C ( trust_policy_filepath ) .
required : false
default : null
version_added : " 2.2 "
trust_policy_filepath :
description :
- The path to the trust policy document that grants an entity permission to assume the role . Mutually exclusive with C ( trust_policy ) .
required : false
default : null
version_added : " 2.2 "
2015-02-17 21:22:40 +01:00
access_key_state :
description :
- When type is user , it creates , removes , deactivates or activates a user ' s access key(s). Note that actions apply only to keys specified.
required : false
default : null
choices : [ " create " , " remove " , " active " , " inactive " ]
key_count :
description :
- When access_key_state is create it will ensure this quantity of keys are present . Defaults to 1.
required : false
default : ' 1 '
access_key_ids :
description :
- A list of the keys that you want impacted by the access_key_state paramter .
groups :
description :
- A list of groups the user should belong to . When update , will gracefully remove groups not listed .
required : false
default : null
password :
description :
- When type is user and state is present , define the users login password . Also works with update . Note that always returns changed .
required : false
default : null
update_password :
required : false
default : always
choices : [ ' always ' , ' on_create ' ]
description :
- C ( always ) will update passwords if they differ . C ( on_create ) will only set the password for newly created users .
notes :
- ' Currently boto does not support the removal of Managed Policies, the module will error out if your user/group/role has managed policies when you try to do state=absent. They will need to be removed manually. '
2015-10-07 22:16:24 +02:00
author :
2015-06-15 20:41:22 +02:00
- " Jonathan I. Davila (@defionscode) "
- " Paul Seiffert (@seiffert) "
2015-10-15 03:58:03 +02:00
extends_documentation_fragment : aws
2015-02-17 21:22:40 +01:00
'''
EXAMPLES = '''
# Basic user creation example
tasks :
- name : Create two new IAM users with API keys
iam :
iam_type : user
name : " {{ item }} "
state : present
password : " {{ temp_pass }} "
access_key_state : create
with_items :
- jcleese
- mpython
# Advanced example, create two new groups and add the pre-existing user
# jdavila to both groups.
task :
- name : Create Two Groups , Mario and Luigi
iam :
iam_type : group
name : " {{ item }} "
state : present
with_items :
- Mario
- Luigi
register : new_groups
- name :
iam :
iam_type : user
name : jdavila
state : update
2015-06-08 14:55:24 +02:00
groups : " {{ item.created_group.group_name }} "
2015-02-17 21:22:40 +01:00
with_items : new_groups . results
2016-06-08 15:23:55 +02:00
# Example of role with custom trust policy for Lambda service
- name : Create IAM role with custom trust relationship
iam :
iam_type : role
name : AAALambdaTestRole
state : present
trust_policy :
Version : ' 2012-10-17 '
Statement :
- Action : sts : AssumeRole
Effect : Allow
Principal :
Service : lambda . amazonaws . com
2015-02-17 21:22:40 +01:00
'''
import json
import itertools
import sys
try :
import boto
import boto . iam
2015-06-19 14:43:40 +02:00
import boto . ec2
2015-02-17 21:22:40 +01:00
HAS_BOTO = True
except ImportError :
HAS_BOTO = False
def boto_exception ( err ) :
''' generic error message handler '''
if hasattr ( err , ' error_message ' ) :
error = err . error_message
elif hasattr ( err , ' message ' ) :
error = err . message
else :
error = ' %s : %s ' % ( Exception , err )
return error
2016-05-20 03:45:37 +02:00
def _paginate ( func , attr ) :
'''
paginates the results from func by continuously passing in
the returned marker if the results were truncated . this returns
an iterator over the items in the returned response . ` attr ` is
the name of the attribute to iterate over in the response .
'''
finished , marker = False , None
while not finished :
res = func ( marker = marker )
for item in getattr ( res , attr ) :
yield item
finished = res . is_truncated == ' false '
if not finished :
marker = res . marker
def list_all_groups ( iam ) :
return [ item [ ' group_name ' ] for item in _paginate ( iam . get_all_groups , ' groups ' ) ]
def list_all_users ( iam ) :
return [ item [ ' user_name ' ] for item in _paginate ( iam . get_all_users , ' users ' ) ]
def list_all_roles ( iam ) :
return [ item [ ' role_name ' ] for item in _paginate ( iam . list_roles , ' roles ' ) ]
def list_all_instance_profiles ( iam ) :
return [ item [ ' instance_profile_name ' ] for item in _paginate ( iam . list_instance_profiles , ' instance_profiles ' ) ]
2015-02-17 21:22:40 +01:00
def create_user ( module , iam , name , pwd , path , key_state , key_count ) :
key_qty = 0
keys = [ ]
try :
user_meta = iam . create_user (
name , path ) . create_user_response . create_user_result . user
changed = True
if pwd is not None :
pwd = iam . create_login_profile ( name , pwd )
if key_state in [ ' create ' ] :
if key_count :
while key_count > key_qty :
keys . append ( iam . create_access_key (
user_name = name ) . create_access_key_response . \
create_access_key_result . \
access_key )
key_qty + = 1
else :
keys = None
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = False , msg = str ( err ) )
else :
user_info = dict ( created_user = user_meta , password = pwd , access_keys = keys )
return ( user_info , changed )
def delete_user ( module , iam , name ) :
2015-11-04 14:54:46 +01:00
del_meta = ' '
2015-02-17 21:22:40 +01:00
try :
current_keys = [ ck [ ' access_key_id ' ] for ck in
iam . get_all_access_keys ( name ) . list_access_keys_result . access_key_metadata ]
for key in current_keys :
iam . delete_access_key ( key , name )
2015-11-04 14:54:46 +01:00
try :
login_profile = iam . get_login_profiles ( name ) . get_login_profile_response
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-11-04 14:54:46 +01:00
error_msg = boto_exception ( err )
if ( ' Cannot find Login Profile ' ) in error_msg :
del_meta = iam . delete_user ( name ) . delete_user_response
2016-05-20 16:26:19 +02:00
else :
iam . delete_login_profile ( name )
del_meta = iam . delete_user ( name ) . delete_user_response
2015-11-04 14:54:46 +01:00
except Exception as ex :
module . fail_json ( changed = False , msg = " delete failed %s " % ex )
2015-02-17 21:22:40 +01:00
if ( ' must detach all policies first ' ) in error_msg :
for policy in iam . get_all_user_policies ( name ) . list_user_policies_result . policy_names :
iam . delete_user_policy ( name , policy )
try :
del_meta = iam . delete_user ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' must detach all policies first ' ) in error_msg :
module . fail_json ( changed = changed , msg = " All inline polices have been removed. Though it appears "
" that %s has Managed Polices. This is not "
" currently supported by boto. Please detach the polices "
" through the console and try again. " % name )
else :
2015-11-04 14:54:46 +01:00
module . fail_json ( changed = changed , msg = str ( error_msg ) )
2015-02-17 21:22:40 +01:00
else :
changed = True
return del_meta , name , changed
else :
changed = True
return del_meta , name , changed
def update_user ( module , iam , name , new_name , new_path , key_state , key_count , keys , pwd , updated ) :
changed = False
name_change = False
if updated and new_name :
name = new_name
try :
current_keys , status = \
[ ck [ ' access_key_id ' ] for ck in
iam . get_all_access_keys ( name ) . list_access_keys_result . access_key_metadata ] , \
[ ck [ ' status ' ] for ck in
iam . get_all_access_keys ( name ) . list_access_keys_result . access_key_metadata ]
key_qty = len ( current_keys )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ' cannot be found ' in error_msg and updated :
current_keys , status = \
[ ck [ ' access_key_id ' ] for ck in
iam . get_all_access_keys ( new_name ) . list_access_keys_result . access_key_metadata ] , \
[ ck [ ' status ' ] for ck in
iam . get_all_access_keys ( new_name ) . list_access_keys_result . access_key_metadata ]
name = new_name
else :
module . fail_json ( changed = False , msg = str ( err ) )
updated_key_list = { }
if new_name or new_path :
c_path = iam . get_user ( name ) . get_user_result . user [ ' path ' ]
if ( name != new_name ) or ( c_path != new_path ) :
changed = True
try :
if not updated :
user = iam . update_user (
name , new_user_name = new_name , new_path = new_path ) . update_user_response . response_metadata
else :
user = iam . update_user (
name , new_path = new_path ) . update_user_response . response_metadata
user [ ' updates ' ] = dict (
old_username = name , new_username = new_name , old_path = c_path , new_path = new_path )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
module . fail_json ( changed = False , msg = str ( err ) )
else :
if not updated :
name_change = True
if pwd :
try :
iam . update_login_profile ( name , pwd )
changed = True
except boto . exception . BotoServerError :
try :
iam . create_login_profile ( name , pwd )
changed = True
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( str ( err ) )
if ' Password does not conform to the account password policy ' in error_msg :
module . fail_json ( changed = False , msg = " Passsword doesn ' t conform to policy " )
else :
module . fail_json ( msg = error_msg )
if key_state == ' create ' :
try :
while key_count > key_qty :
new_key = iam . create_access_key (
user_name = name ) . create_access_key_response . create_access_key_result . access_key
key_qty + = 1
changed = True
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = False , msg = str ( err ) )
if keys and key_state :
for access_key in keys :
if access_key in current_keys :
for current_key , current_key_state in zip ( current_keys , status ) :
if key_state != current_key_state . lower ( ) :
try :
iam . update_access_key (
access_key , key_state . capitalize ( ) , user_name = name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = False , msg = str ( err ) )
else :
changed = True
if key_state == ' remove ' :
try :
iam . delete_access_key ( access_key , user_name = name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = False , msg = str ( err ) )
else :
changed = True
try :
final_keys , final_key_status = \
[ ck [ ' access_key_id ' ] for ck in
iam . get_all_access_keys ( name ) .
list_access_keys_result .
access_key_metadata ] , \
[ ck [ ' status ' ] for ck in
iam . get_all_access_keys ( name ) .
list_access_keys_result .
access_key_metadata ]
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
for fk , fks in zip ( final_keys , final_key_status ) :
updated_key_list . update ( { fk : fks } )
return name_change , updated_key_list , changed
def set_users_groups ( module , iam , name , groups , updated = None ,
new_name = None ) :
""" Sets groups for a user, will purge groups not explictly passed, while
retaining pre - existing groups that also are in the new list .
"""
changed = False
if updated :
name = new_name
try :
orig_users_groups = [ og [ ' group_name ' ] for og in iam . get_groups_for_user (
name ) . list_groups_for_user_result . groups ]
remove_groups = [
rg for rg in frozenset ( orig_users_groups ) . difference ( groups ) ]
new_groups = [
ng for ng in frozenset ( groups ) . difference ( orig_users_groups ) ]
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
else :
if len ( orig_users_groups ) > 0 :
for new in new_groups :
iam . add_user_to_group ( new , name )
for rm in remove_groups :
iam . remove_user_from_group ( rm , name )
else :
for group in groups :
try :
iam . add_user_to_group ( group , name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' The group with name %s cannot be found. ' % group ) in error_msg :
module . fail_json ( changed = False , msg = " Group %s doesn ' t exist " % group )
if len ( remove_groups ) > 0 or len ( new_groups ) > 0 :
changed = True
return ( groups , changed )
2015-06-08 14:55:24 +02:00
def create_group ( module = None , iam = None , name = None , path = None ) :
2015-02-17 21:22:40 +01:00
changed = False
try :
iam . create_group (
name , path ) . create_group_response . create_group_result . group
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
else :
changed = True
return name , changed
2015-06-09 16:27:15 +02:00
def delete_group ( module = None , iam = None , name = None ) :
2015-02-17 21:22:40 +01:00
changed = False
try :
iam . delete_group ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' must detach all policies first ' ) in error_msg :
for policy in iam . get_all_group_policies ( name ) . list_group_policies_result . policy_names :
iam . delete_group_policy ( name , policy )
try :
iam . delete_group ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' must detach all policies first ' ) in error_msg :
module . fail_json ( changed = changed , msg = " All inline polices have been removed. Though it appears "
" that %s has Managed Polices. This is not "
" currently supported by boto. Please detach the polices "
" through the console and try again. " % name )
else :
module . fail_json ( changed = changed , msg = str ( err ) )
else :
changed = True
else :
changed = True
return changed , name
2015-06-08 14:55:24 +02:00
def update_group ( module = None , iam = None , name = None , new_name = None , new_path = None ) :
2015-02-17 21:22:40 +01:00
changed = False
try :
current_group_path = iam . get_group (
name ) . get_group_response . get_group_result . group [ ' path ' ]
if new_path :
if current_group_path != new_path :
iam . update_group ( name , new_path = new_path )
changed = True
if new_name :
if name != new_name :
iam . update_group ( name , new_group_name = new_name , new_path = new_path )
changed = True
name = new_name
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
return changed , name , new_path , current_group_path
2016-06-08 15:23:55 +02:00
def create_role ( module , iam , name , path , role_list , prof_list , trust_policy_doc ) :
2015-02-17 21:22:40 +01:00
changed = False
2016-05-18 15:06:11 +02:00
iam_role_result = None
instance_profile_result = None
2015-02-17 21:22:40 +01:00
try :
if name not in role_list :
changed = True
2016-06-08 15:23:55 +02:00
iam_role_result = iam . create_role ( name ,
assume_role_policy_document = trust_policy_doc ,
path = path ) . create_role_response . create_role_result . role . role_name
2015-02-17 21:22:40 +01:00
if name not in prof_list :
2016-06-03 19:15:15 +02:00
instance_profile_result = iam . create_instance_profile ( name ,
2016-05-18 15:06:11 +02:00
path = path ) . create_instance_profile_response . create_instance_profile_result . instance_profile
2015-02-17 21:22:40 +01:00
iam . add_role_to_instance_profile ( name , name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
else :
2016-05-20 03:45:37 +02:00
updated_role_list = list_all_roles ( iam )
2016-05-18 15:06:11 +02:00
return changed , updated_role_list , iam_role_result , instance_profile_result
2015-02-17 21:22:40 +01:00
def delete_role ( module , iam , name , role_list , prof_list ) :
changed = False
2016-05-18 15:06:11 +02:00
iam_role_result = None
instance_profile_result = None
2015-02-17 21:22:40 +01:00
try :
if name in role_list :
cur_ins_prof = [ rp [ ' instance_profile_name ' ] for rp in
iam . list_instance_profiles_for_role ( name ) .
list_instance_profiles_for_role_result .
instance_profiles ]
for profile in cur_ins_prof :
iam . remove_role_from_instance_profile ( profile , name )
try :
iam . delete_role ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' must detach all policies first ' ) in error_msg :
for policy in iam . list_role_policies ( name ) . list_role_policies_result . policy_names :
iam . delete_role_policy ( name , policy )
try :
2016-05-18 15:06:11 +02:00
iam_role_result = iam . delete_role ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
error_msg = boto_exception ( err )
if ( ' must detach all policies first ' ) in error_msg :
module . fail_json ( changed = changed , msg = " All inline polices have been removed. Though it appears "
" that %s has Managed Polices. This is not "
" currently supported by boto. Please detach the polices "
" through the console and try again. " % name )
else :
module . fail_json ( changed = changed , msg = str ( err ) )
else :
changed = True
else :
changed = True
for prof in prof_list :
if name == prof :
2016-05-18 15:06:11 +02:00
instance_profile_result = iam . delete_instance_profile ( name )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-02-17 21:22:40 +01:00
module . fail_json ( changed = changed , msg = str ( err ) )
else :
2016-05-20 03:45:37 +02:00
updated_role_list = list_all_roles ( iam )
2016-05-18 15:06:11 +02:00
return changed , updated_role_list , iam_role_result , instance_profile_result
2015-02-17 21:22:40 +01:00
def main ( ) :
argument_spec = ec2_argument_spec ( )
argument_spec . update ( dict (
iam_type = dict (
default = None , required = True , choices = [ ' user ' , ' group ' , ' role ' ] ) ,
groups = dict ( type = ' list ' , default = None , required = False ) ,
state = dict (
default = None , required = True , choices = [ ' present ' , ' absent ' , ' update ' ] ) ,
2015-06-29 21:14:50 +02:00
password = dict ( default = None , required = False , no_log = True ) ,
2015-02-17 21:22:40 +01:00
update_password = dict ( default = ' always ' , required = False , choices = [ ' always ' , ' on_create ' ] ) ,
access_key_state = dict ( default = None , required = False , choices = [
' active ' , ' inactive ' , ' create ' , ' remove ' ,
' Active ' , ' Inactive ' , ' Create ' , ' Remove ' ] ) ,
access_key_ids = dict ( type = ' list ' , default = None , required = False ) ,
key_count = dict ( type = ' int ' , default = 1 , required = False ) ,
name = dict ( default = None , required = False ) ,
2016-06-08 15:23:55 +02:00
trust_policy_filepath = dict ( default = None , required = False ) ,
trust_policy = dict ( type = ' dict ' , default = None , required = False ) ,
2015-02-17 21:22:40 +01:00
new_name = dict ( default = None , required = False ) ,
path = dict ( default = ' / ' , required = False ) ,
new_path = dict ( default = None , required = False )
)
)
module = AnsibleModule (
argument_spec = argument_spec ,
2016-06-08 15:23:55 +02:00
mutually_exclusive = [ [ ' trust_policy ' , ' trust_policy_filepath ' ] ] ,
2015-02-17 21:22:40 +01:00
)
if not HAS_BOTO :
module . fail_json ( msg = ' This module requires boto, please install it ' )
state = module . params . get ( ' state ' ) . lower ( )
iam_type = module . params . get ( ' iam_type ' ) . lower ( )
groups = module . params . get ( ' groups ' )
name = module . params . get ( ' name ' )
new_name = module . params . get ( ' new_name ' )
password = module . params . get ( ' password ' )
update_pw = module . params . get ( ' update_password ' )
path = module . params . get ( ' path ' )
new_path = module . params . get ( ' new_path ' )
key_count = module . params . get ( ' key_count ' )
key_state = module . params . get ( ' access_key_state ' )
2016-06-08 15:23:55 +02:00
trust_policy = module . params . get ( ' trust_policy ' )
trust_policy_filepath = module . params . get ( ' trust_policy_filepath ' )
2016-04-19 19:53:21 +02:00
key_ids = module . params . get ( ' access_key_ids ' )
2016-06-08 15:23:55 +02:00
2015-02-17 21:22:40 +01:00
if key_state :
key_state = key_state . lower ( )
if any ( [ n in key_state for n in [ ' active ' , ' inactive ' ] ] ) and not key_ids :
module . fail_json ( changed = False , msg = " At least one access key has to be defined in order "
" to use ' active ' or ' inactive ' " )
if iam_type == ' user ' and module . params . get ( ' password ' ) is not None :
pwd = module . params . get ( ' password ' )
elif iam_type != ' user ' and module . params . get ( ' password ' ) is not None :
module . fail_json ( msg = " a password is being specified when the iam_type "
" is not user. Check parameters " )
else :
pwd = None
if iam_type != ' user ' and ( module . params . get ( ' access_key_state ' ) is not None or
module . params . get ( ' access_key_id ' ) is not None ) :
module . fail_json ( msg = " the IAM type must be user, when IAM access keys "
" are being modified. Check parameters " )
if iam_type == ' role ' and state == ' update ' :
module . fail_json ( changed = False , msg = " iam_type: role, cannot currently be updated, "
" please specificy present or absent " )
2016-06-08 15:23:55 +02:00
# check if trust_policy is present -- it can be inline JSON or a file path to a JSON file
if trust_policy_filepath :
try :
with open ( trust_policy_filepath , ' r ' ) as json_data :
trust_policy_doc = json . dumps ( json . load ( json_data ) )
except Exception as e :
module . fail_json ( msg = str ( e ) + ' : ' + trust_policy_filepath )
elif trust_policy :
try :
trust_policy_doc = json . dumps ( trust_policy )
except Exception as e :
module . fail_json ( msg = str ( e ) + ' : ' + trust_policy )
else :
trust_policy_doc = None
2015-06-23 20:31:48 +02:00
region , ec2_url , aws_connect_kwargs = get_aws_connection_info ( module )
2015-02-17 21:22:40 +01:00
try :
2015-10-22 01:12:58 +02:00
if region :
2015-11-06 10:02:00 +01:00
iam = connect_to_aws ( boto . iam , region , * * aws_connect_kwargs )
2015-10-22 01:12:58 +02:00
else :
iam = boto . iam . connection . IAMConnection ( * * aws_connect_kwargs )
2016-06-02 21:56:48 +02:00
except boto . exception . NoAuthHandlerFound as e :
2015-02-17 21:22:40 +01:00
module . fail_json ( msg = str ( e ) )
result = { }
changed = False
2015-09-14 07:43:49 +02:00
try :
2016-05-20 03:45:37 +02:00
orig_group_list = list_all_groups ( iam )
orig_user_list = list_all_users ( iam )
orig_role_list = list_all_roles ( iam )
orig_prof_list = list_all_instance_profiles ( iam )
2016-06-02 21:56:48 +02:00
except boto . exception . BotoServerError as err :
2015-09-15 23:25:22 +02:00
module . fail_json ( msg = err . message )
2015-02-17 21:22:40 +01:00
if iam_type == ' user ' :
been_updated = False
user_groups = None
user_exists = any ( [ n in [ name , new_name ] for n in orig_user_list ] )
if user_exists :
current_path = iam . get_user ( name ) . get_user_result . user [ ' path ' ]
if not new_path and current_path != path :
new_path = path
path = current_path
if state == ' present ' and not user_exists and not new_name :
( meta , changed ) = create_user (
module , iam , name , password , path , key_state , key_count )
keys = iam . get_all_access_keys ( name ) . list_access_keys_result . \
access_key_metadata
if groups :
( user_groups , changed ) = set_users_groups (
module , iam , name , groups , been_updated , new_name )
module . exit_json (
user_meta = meta , groups = user_groups , keys = keys , changed = changed )
elif state in [ ' present ' , ' update ' ] and user_exists :
if update_pw == ' on_create ' :
password = None
if name not in orig_user_list and new_name in orig_user_list :
been_updated = True
name_change , key_list , user_changed = update_user (
module , iam , name , new_name , new_path , key_state , key_count , key_ids , password , been_updated )
if name_change and new_name :
orig_name = name
name = new_name
if groups :
user_groups , groups_changed = set_users_groups (
module , iam , name , groups , been_updated , new_name )
if groups_changed == user_changed :
changed = groups_changed
else :
changed = True
else :
changed = user_changed
if new_name and new_path :
module . exit_json ( changed = changed , groups = user_groups , old_user_name = orig_name ,
new_user_name = new_name , old_path = path , new_path = new_path , keys = key_list )
elif new_name and not new_path and not been_updated :
module . exit_json (
changed = changed , groups = user_groups , old_user_name = orig_name , new_user_name = new_name , keys = key_list )
elif new_name and not new_path and been_updated :
module . exit_json (
changed = changed , groups = user_groups , user_name = new_name , keys = key_list , key_state = key_state )
elif not new_name and new_path :
module . exit_json (
changed = changed , groups = user_groups , user_name = name , old_path = path , new_path = new_path , keys = key_list )
else :
module . exit_json (
changed = changed , groups = user_groups , user_name = name , keys = key_list )
2015-11-04 14:54:46 +01:00
2015-02-17 21:22:40 +01:00
elif state == ' update ' and not user_exists :
module . fail_json (
2016-01-13 00:18:30 +01:00
msg = " The user %s does not exist. No update made. " % name )
2015-11-04 14:54:46 +01:00
2015-02-17 21:22:40 +01:00
elif state == ' absent ' :
2015-11-04 14:54:46 +01:00
if user_exists :
try :
set_users_groups ( module , iam , name , ' ' )
del_meta , name , changed = delete_user ( module , iam , name )
module . exit_json ( deleted_user = name , changed = changed )
except Exception as ex :
module . fail_json ( changed = changed , msg = str ( ex ) )
2015-02-17 21:22:40 +01:00
else :
module . exit_json (
changed = False , msg = " User %s is already absent from your AWS IAM users " % name )
elif iam_type == ' group ' :
group_exists = name in orig_group_list
if state == ' present ' and not group_exists :
2016-06-03 19:15:15 +02:00
new_group , changed = create_group ( module = module , iam = iam , name = name , path = path )
2015-02-17 21:22:40 +01:00
module . exit_json ( changed = changed , group_name = new_group )
elif state in [ ' present ' , ' update ' ] and group_exists :
changed , updated_name , updated_path , cur_path = update_group (
2016-06-03 19:15:15 +02:00
module = module , iam = iam , name = name , new_name = new_name ,
new_path = new_path )
2015-02-17 21:22:40 +01:00
if new_path and new_name :
module . exit_json ( changed = changed , old_group_name = name ,
new_group_name = updated_name , old_path = cur_path ,
new_group_path = updated_path )
if new_path and not new_name :
module . exit_json ( changed = changed , group_name = name ,
old_path = cur_path ,
new_group_path = updated_path )
if not new_path and new_name :
module . exit_json ( changed = changed , old_group_name = name ,
new_group_name = updated_name , group_path = cur_path )
if not new_path and not new_name :
module . exit_json (
changed = changed , group_name = name , group_path = cur_path )
2015-11-04 14:54:46 +01:00
2015-02-17 21:22:40 +01:00
elif state == ' update ' and not group_exists :
module . fail_json (
2016-06-03 19:15:15 +02:00
changed = changed , msg = " Update Failed. Group %s doesn ' t seem to exist! " % name )
2015-11-04 14:54:46 +01:00
2015-02-17 21:22:40 +01:00
elif state == ' absent ' :
if name in orig_group_list :
2016-06-03 19:15:15 +02:00
removed_group , changed = delete_group ( module = module , iam = iam , name = name )
2015-02-17 21:22:40 +01:00
module . exit_json ( changed = changed , delete_group = removed_group )
else :
module . exit_json ( changed = changed , msg = " Group already absent " )
elif iam_type == ' role ' :
role_list = [ ]
if state == ' present ' :
2016-05-18 15:06:11 +02:00
changed , role_list , role_result , instance_profile_result = create_role (
2016-06-08 15:23:55 +02:00
module , iam , name , path , orig_role_list , orig_prof_list , trust_policy_doc )
2015-02-17 21:22:40 +01:00
elif state == ' absent ' :
2016-05-18 15:06:11 +02:00
changed , role_list , role_result , instance_profile_result = delete_role (
2015-02-17 21:22:40 +01:00
module , iam , name , orig_role_list , orig_prof_list )
elif state == ' update ' :
module . fail_json (
changed = False , msg = ' Role update not currently supported by boto. ' )
2016-05-18 15:06:11 +02:00
module . exit_json ( changed = changed , roles = role_list , role_result = role_result ,
instance_profile_result = instance_profile_result )
2015-02-17 21:22:40 +01:00
from ansible . module_utils . basic import *
from ansible . module_utils . ec2 import *
main ( )