AWS IAM User No Policies Audit: SOC2 Compliance

This runbook ensures that AWS IAM users don't have direct policies attached, adhering to SOC2 security guidelines. It mandates permissions be granted via group memberships or IAM roles, enhancing security and simplifying permission management. This audit is key in maintaining structured access control, crucial for SOC2 compliance in cloud environments.

  1. 1

    This task involves identifying IAM users in an AWS environment who have individual policies attached to their accounts. This is key for security and compliance, ensuring permissions are managed through group memberships or role assumptions, rather than direct attachments, for better access control and security practices.

    import boto3 from botocore.exceptions import ClientError, BotoCoreError creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def check_iam_users_for_attached_policies(): """ Check if any IAM users have policies attached directly to them. """ iam = boto3.client('iam',aws_access_key_id=access_key,aws_secret_access_key=secret_key) non_compliant_users = 0 total_users = 0 try: # Initialize pagination paginator = iam.get_paginator('list_users') for page in paginator.paginate(): for user in page['Users']: total_users += 1 username = user['UserName'] # Check for attached user policies attached_policies = iam.list_attached_user_policies(UserName=username)['AttachedPolicies'] if attached_policies: print(f"Non-compliant: User '{username}' has direct policies attached.") non_compliant_users += 1 else: print(f"Compliant: User '{username}' has no direct policies attached.") print(f"\nTotal users checked: {total_users}") print(f"Non-compliant users: {non_compliant_users}") except ClientError as e: print(f"AWS ClientError: {e.response['Error']['Message']}") except BotoCoreError as e: print(f"BotoCoreError: {e}") except Exception as e: print(f"An unexpected error occurred: {e}") # Example usage check_iam_users_for_attached_policies() context.skip_sub_tasks=True
    copied
    1
    1. 1.1

      This task manages user permissions in AWS by confirming the existence of both IAM users and groups, ensuring users aren't already in the target group, and then adding them if necessary. This process streamlines user access management and maintains organized, best-practice-based user-group associations in AWS IAM.

      import boto3 from botocore.exceptions import ClientError creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def add_user_to_group(user_name, group_name): """ Adds an IAM user to an IAM group, after checking if both exist and if the user is not already in the group. :param user_name: The name of the IAM user. :param group_name: The name of the IAM group. """ # Create an IAM client iam_client = boto3.client('iam',aws_access_key_id=access_key,aws_secret_access_key=secret_key) try: # Check if the user exists iam_client.get_user(UserName=user_name) except ClientError as error: if error.response['Error']['Code'] == 'NoSuchEntity': print(f"The user '{user_name}' does not exist.") return else: raise try: # Check if the group exists and if the user is already a member response = iam_client.get_group(GroupName=group_name) if any(user['UserName'] == user_name for user in response['Users']): print(f"User '{user_name}' is already a member of the group '{group_name}'.") return except ClientError as error: if error.response['Error']['Code'] == 'NoSuchEntity': print(f"The group '{group_name}' does not exist.") return else: raise try: # Add user to the group iam_client.add_user_to_group( GroupName=group_name, UserName=user_name ) print(f"User '{user_name}' has been successfully added to the group '{group_name}'.") except ClientError as error: # Handle other possible errors print(f"Unexpected error: {error}") except Exception as e: # Handle any other exception print(f"An error occurred: {e}") # Example usage #username = 'test_user' #groupname = 'your-group-name' add_user_to_group(username, groupname) context.proceed=False
      copied
      1.1
    2. 1.2

      This task assigns a policy to an IAM user, enabling them to assume a specified IAM role. This key security measure allows controlled, temporary access elevation in line with the principle of least privilege. It's essential for secure and efficient permission management in AWS. Note:- This will directly attach a policy to the AWS IAM User.

      import boto3 from botocore.exceptions import ClientError import json creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def get_aws_account_id(): """ Retrieves the AWS account ID using STS. """ sts_client = boto3.client('sts',aws_access_key_id=access_key,aws_secret_access_key=secret_key,region_name='us-east-1') try: account_id = sts_client.get_caller_identity()["Account"] return account_id except ClientError as error: print(f"Error retrieving AWS account ID: {error}") return None def get_policy_arn(iam_client, policy_name): """ Retrieves the ARN of a given policy. :param iam_client: The IAM client instance. :param policy_name: The name of the policy. :return: The ARN of the policy or None if not found. """ try: policy = iam_client.get_policy(PolicyArn=f"arn:aws:iam::{get_aws_account_id()}:policy/{policy_name}") return policy['Policy']['Arn'] except ClientError: return None def check_role_exists(iam_client, role_name): """ Checks if the specified IAM role exists. :param iam_client: The IAM client instance. :param role_name: The name of the IAM role to check. :return: True if the role exists, False otherwise. """ try: iam_client.get_role(RoleName=role_name) return True except ClientError as error: if error.response['Error']['Code'] == 'NoSuchEntity': return False else: raise def attach_role_to_user(user_name, role_name): """ Attaches a policy to a user that allows the user to assume a specified role. :param user_name: The name of the IAM user. :param role_name: The name of the IAM role. """ # Create an IAM client iam_client = boto3.client('iam',aws_access_key_id=access_key,aws_secret_access_key=secret_key) # Get AWS account ID account_id = get_aws_account_id() if account_id is None: print("Failed to retrieve AWS account ID. Exiting function.") return policy_name = f"AllowAssumeRole-{role_name}" policy_arn = get_policy_arn(iam_client, policy_name) policy_document = { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": f"arn:aws:iam::{account_id}:role/{role_name}" } ] } # Check if the role exists if not check_role_exists(iam_client, role_name): print(f"The role '{role_name}' does not exist. Exiting function.") return # Create or update policy if policy_arn: print(f"Policy {policy_name} already exists. Updating policy.") try: iam_client.create_policy_version( PolicyArn=policy_arn, PolicyDocument=json.dumps(policy_document), SetAsDefault=True ) except ClientError as error: print(f"Failed to update policy: {error}") return else: try: policy_response = iam_client.create_policy( PolicyName=policy_name, PolicyDocument=json.dumps(policy_document) ) policy_arn = policy_response['Policy']['Arn'] except ClientError as error: print(f"Failed to create policy: {error}") return # Attach the policy to the user try: iam_client.attach_user_policy( UserName=user_name, PolicyArn=policy_arn ) print(f"Policy {policy_name} attached to user {user_name} allowing to assume role {role_name}.") except ClientError as error: print(f"Failed to attach policy to user: {error}") # Example usage #username = 'test_user' #rolename = 'AWSServiceRoleForECS' attach_role_to_user(username, rolename) context.proceed=False
      copied
      1.2