Fix AWS iam_user remove (#59079)
* Make iam_user not fail on user deletion. - Use guard clause on already absent user - Refactor, use variable instead nested dict - Ensure needed prerequisites for boto3 delete_user successfully - Use AnsibleAWSModule on iam_user. - Fix fail_json_aws calls * Add s-hertel comments to PR
This commit is contained in:
parent
6046386dba
commit
f0cadb9843
1 changed files with 79 additions and 35 deletions
|
@ -99,14 +99,14 @@ user:
|
|||
'''
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.aws.core import AnsibleAWSModule
|
||||
from ansible.module_utils.ec2 import camel_dict_to_snake_dict, ec2_argument_spec, get_aws_connection_info, boto3_conn
|
||||
from ansible.module_utils.ec2 import HAS_BOTO3
|
||||
|
||||
import traceback
|
||||
|
||||
try:
|
||||
from botocore.exceptions import ClientError, ParamValidationError
|
||||
from botocore.exceptions import ClientError, ParamValidationError, BotoCoreError
|
||||
except ImportError:
|
||||
pass # caught by imported HAS_BOTO3
|
||||
|
||||
|
@ -227,39 +227,73 @@ def create_or_update_user(connection, module):
|
|||
|
||||
def destroy_user(connection, module):
|
||||
|
||||
params = dict()
|
||||
params['UserName'] = module.params.get('name')
|
||||
user_name = module.params.get('name')
|
||||
|
||||
if get_user(connection, module, params['UserName']):
|
||||
# Check mode means we would remove this user
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
# Remove any attached policies otherwise deletion fails
|
||||
try:
|
||||
for policy in get_attached_policy_list(connection, module, params['UserName']):
|
||||
connection.detach_user_policy(UserName=params['UserName'], PolicyArn=policy['PolicyArn'])
|
||||
except ClientError as e:
|
||||
module.fail_json(msg="Unable to detach policy {0} from user {1}: {2}".format(
|
||||
policy['PolicyArn'], params['UserName'], to_native(e)),
|
||||
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
|
||||
except ParamValidationError as e:
|
||||
module.fail_json(msg="Unable to detach policy {0} from user {1}: {2}".format(
|
||||
policy['PolicyArn'], params['UserName'], to_native(e)),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
try:
|
||||
connection.delete_user(**params)
|
||||
except ClientError as e:
|
||||
module.fail_json(msg="Unable to delete user {0}: {1}".format(params['UserName'], to_native(e)),
|
||||
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
|
||||
except ParamValidationError as e:
|
||||
module.fail_json(msg="Unable to delete user {0}: {1}".format(params['UserName'], to_native(e)),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
else:
|
||||
user = get_user(connection, module, user_name)
|
||||
# User is not present
|
||||
if not user:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
# Check mode means we would remove this user
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
# Remove any attached policies otherwise deletion fails
|
||||
try:
|
||||
for policy in get_attached_policy_list(connection, module, user_name):
|
||||
connection.detach_user_policy(UserName=user_name, PolicyArn=policy['PolicyArn'])
|
||||
except (ClientError, BotoCoreError) as e:
|
||||
module.fail_json_aws(e, msg="Unable to delete user {0}".format(user_name))
|
||||
|
||||
try:
|
||||
# Remove user's access keys
|
||||
access_keys = connection.list_access_keys(UserName=user_name)["AccessKeyMetadata"]
|
||||
for access_key in access_keys:
|
||||
connection.delete_access_key(UserName=user_name, AccessKeyId=access_key["AccessKeyId"])
|
||||
|
||||
# Remove user's login profile (console password)
|
||||
delete_user_login_profile(connection, module, user_name)
|
||||
|
||||
# Remove user's ssh public keys
|
||||
ssh_public_keys = connection.list_ssh_public_keys(UserName=user_name)["SSHPublicKeys"]
|
||||
for ssh_public_key in ssh_public_keys:
|
||||
connection.delete_ssh_public_key(UserName=user_name, SSHPublicKeyId=ssh_public_key["SSHPublicKeyId"])
|
||||
|
||||
# Remove user's service specific credentials
|
||||
service_credentials = connection.list_service_specific_credentials(UserName=user_name)["ServiceSpecificCredentials"]
|
||||
for service_specific_credential in service_credentials:
|
||||
connection.delete_service_specific_credential(
|
||||
UserName=user_name,
|
||||
ServiceSpecificCredentialId=service_specific_credential["ServiceSpecificCredentialId"]
|
||||
)
|
||||
|
||||
# Remove user's signing certificates
|
||||
signing_certificates = connection.list_signing_certificates(UserName=user_name)["Certificates"]
|
||||
for signing_certificate in signing_certificates:
|
||||
connection.delete_signing_certificate(
|
||||
UserName=user_name,
|
||||
CertificateId=signing_certificate["CertificateId"]
|
||||
)
|
||||
|
||||
# Remove user's MFA devices
|
||||
mfa_devices = connection.list_mfa_devices(UserName=user_name)["MFADevices"]
|
||||
for mfa_device in mfa_devices:
|
||||
connection.deactivate_mfa_device(UserName=user_name, SerialNumber=mfa_device["SerialNumber"])
|
||||
|
||||
# Remove user's inline policies
|
||||
inline_policies = connection.list_user_policies(UserName=user_name)["PolicyNames"]
|
||||
for policy_name in inline_policies:
|
||||
connection.delete_user_policy(UserName=user_name, PolicyName=policy_name)
|
||||
|
||||
# Remove user's group membership
|
||||
user_groups = connection.list_groups_for_user(UserName=user_name)["Groups"]
|
||||
for group in user_groups:
|
||||
connection.remove_user_from_group(UserName=user_name, GroupName=group["GroupName"])
|
||||
|
||||
connection.delete_user(UserName=user_name)
|
||||
except (ClientError, BotoCoreError) as e:
|
||||
module.fail_json_aws(e, msg="Unable to delete user {0}".format(user_name))
|
||||
|
||||
module.exit_json(changed=True)
|
||||
|
||||
|
||||
|
@ -286,8 +320,18 @@ def get_attached_policy_list(connection, module, name):
|
|||
if e.response['Error']['Code'] == 'NoSuchEntity':
|
||||
return None
|
||||
else:
|
||||
module.fail_json(msg="Unable to get policies for user {0}: {1}".format(name, to_native(e)),
|
||||
**camel_dict_to_snake_dict(e.response))
|
||||
module.fail_json_aws(e, msg="Unable to get policies for user {0}".format(name))
|
||||
|
||||
|
||||
def delete_user_login_profile(connection, module, user_name):
|
||||
|
||||
try:
|
||||
return connection.delete_login_profile(UserName=user_name)
|
||||
except ClientError as e:
|
||||
if e.response["Error"]["Code"] == "NoSuchEntity":
|
||||
return None
|
||||
else:
|
||||
module.fail_json_aws(e, msg="Unable to delete login profile for user {0}".format(user_name))
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -302,7 +346,7 @@ def main():
|
|||
)
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
module = AnsibleAWSModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue