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._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 camel_dict_to_snake_dict, ec2_argument_spec, get_aws_connection_info, boto3_conn
|
||||||
from ansible.module_utils.ec2 import HAS_BOTO3
|
from ansible.module_utils.ec2 import HAS_BOTO3
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from botocore.exceptions import ClientError, ParamValidationError
|
from botocore.exceptions import ClientError, ParamValidationError, BotoCoreError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass # caught by imported HAS_BOTO3
|
pass # caught by imported HAS_BOTO3
|
||||||
|
|
||||||
|
@ -227,38 +227,72 @@ def create_or_update_user(connection, module):
|
||||||
|
|
||||||
def destroy_user(connection, module):
|
def destroy_user(connection, module):
|
||||||
|
|
||||||
params = dict()
|
user_name = module.params.get('name')
|
||||||
params['UserName'] = module.params.get('name')
|
|
||||||
|
user = get_user(connection, module, user_name)
|
||||||
|
# User is not present
|
||||||
|
if not user:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
if get_user(connection, module, params['UserName']):
|
|
||||||
# Check mode means we would remove this user
|
# Check mode means we would remove this user
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(changed=True)
|
module.exit_json(changed=True)
|
||||||
|
|
||||||
# Remove any attached policies otherwise deletion fails
|
# Remove any attached policies otherwise deletion fails
|
||||||
try:
|
try:
|
||||||
for policy in get_attached_policy_list(connection, module, params['UserName']):
|
for policy in get_attached_policy_list(connection, module, user_name):
|
||||||
connection.detach_user_policy(UserName=params['UserName'], PolicyArn=policy['PolicyArn'])
|
connection.detach_user_policy(UserName=user_name, PolicyArn=policy['PolicyArn'])
|
||||||
except ClientError as e:
|
except (ClientError, BotoCoreError) as e:
|
||||||
module.fail_json(msg="Unable to detach policy {0} from user {1}: {2}".format(
|
module.fail_json_aws(e, msg="Unable to delete user {0}".format(user_name))
|
||||||
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:
|
try:
|
||||||
connection.delete_user(**params)
|
# Remove user's access keys
|
||||||
except ClientError as e:
|
access_keys = connection.list_access_keys(UserName=user_name)["AccessKeyMetadata"]
|
||||||
module.fail_json(msg="Unable to delete user {0}: {1}".format(params['UserName'], to_native(e)),
|
for access_key in access_keys:
|
||||||
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
|
connection.delete_access_key(UserName=user_name, AccessKeyId=access_key["AccessKeyId"])
|
||||||
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:
|
# Remove user's login profile (console password)
|
||||||
module.exit_json(changed=False)
|
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)
|
module.exit_json(changed=True)
|
||||||
|
|
||||||
|
@ -286,8 +320,18 @@ def get_attached_policy_list(connection, module, name):
|
||||||
if e.response['Error']['Code'] == 'NoSuchEntity':
|
if e.response['Error']['Code'] == 'NoSuchEntity':
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
module.fail_json(msg="Unable to get policies for user {0}: {1}".format(name, to_native(e)),
|
module.fail_json_aws(e, msg="Unable to get policies for user {0}".format(name))
|
||||||
**camel_dict_to_snake_dict(e.response))
|
|
||||||
|
|
||||||
|
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():
|
def main():
|
||||||
|
@ -302,7 +346,7 @@ def main():
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
module = AnsibleModule(
|
module = AnsibleAWSModule(
|
||||||
argument_spec=argument_spec,
|
argument_spec=argument_spec,
|
||||||
supports_check_mode=True
|
supports_check_mode=True
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue