import boto3
from botocore.exceptions import ClientError
import json
import time

# A script to demonstrate IAM user, group, and policy management using Boto3.
# This script creates a user, a group, a custom policy for S3 read-only access,
# attaches the policy to the group, and adds the user to the group.
# Finally, it cleans up all created resources.

# --- Configuration ---
REGION = "us-east-1"
USER_NAME = "MyBoto3User"
GROUP_NAME = "MyBoto3Group"
POLICY_NAME = "MyBoto3S3ReadOnlyPolicy"

iam_client = boto3.client('iam', region_name=REGION)

def create_iam_user():
    """Creates an IAM user."""
    print(f"--- Creating IAM User: {USER_NAME} ---")
    try:
        iam_client.create_user(UserName=USER_NAME)
        print(f"User '{USER_NAME}' created.")
    except ClientError as e:
        if e.response['Error']['Code'] == 'EntityAlreadyExists':
            print(f"User '{USER_NAME}' already exists. Skipping creation.")
        else:
            raise e

def create_iam_group():
    """Creates an IAM group."""
    print(f"\n--- Creating IAM Group: {GROUP_NAME} ---")
    try:
        iam_client.create_group(GroupName=GROUP_NAME)
        print(f"Group '{GROUP_NAME}' created.")
    except ClientError as e:
        if e.response['Error']['Code'] == 'EntityAlreadyExists':
            print(f"Group '{GROUP_NAME}' already exists. Skipping creation.")
        else:
            raise e

def create_iam_policy():
    """Creates a custom IAM policy for S3 read-only access."""
    print(f"\n--- Creating Custom IAM Policy: {POLICY_NAME} ---")
    policy_document = {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:Get*",
            "s3:List*"
          ],
          "Resource": "*"
        }
      ]
    }
    try:
        response = iam_client.create_policy(
            PolicyName=POLICY_NAME,
            PolicyDocument=json.dumps(policy_document)
        )
        policy_arn = response['Policy']['Arn']
        print(f"Policy '{POLICY_NAME}' created with ARN: {policy_arn}")
        time.sleep(5) # Give IAM a moment to propagate the policy
        return policy_arn
    except ClientError as e:
        if e.response['Error']['Code'] == 'EntityAlreadyExists':
            print(f"Policy '{POLICY_NAME}' already exists. Fetching ARN.")
            return iam_client.get_policy(PolicyArn=f"arn:aws:iam::{iam_client.get_caller_identity()['Account']}:policy/{POLICY_NAME}")['Policy']['Arn']
        else:
            raise e

def attach_policy_to_group(policy_arn):
    """Attaches the policy to the group."""
    print(f"\n--- Attaching Policy '{POLICY_NAME}' to Group '{GROUP_NAME}' ---")
    iam_client.attach_group_policy(
        GroupName=GROUP_NAME,
        PolicyArn=policy_arn
    )
    print("Policy attached to group.")

def add_user_to_group():
    """Adds the user to the group."""
    print(f"\n--- Adding User '{USER_NAME}' to Group '{GROUP_NAME}' ---")
    iam_client.add_user_to_group(
        UserName=USER_NAME,
        GroupName=GROUP_NAME
    )
    print(f"User added to group. '{USER_NAME}' now has S3 read-only access.")

def cleanup_resources(policy_arn):
    """Cleans up all created IAM resources."""
    print(f"\n--- Cleaning up resources ---")
    
    # Remove user from group
    print("Removing user from group...")
    try:
        iam_client.remove_user_from_group(UserName=USER_NAME, GroupName=GROUP_NAME)
    except ClientError as e:
        if e.response['Error']['Code'] != 'NoSuchEntity':
            print(f"Error removing user from group: {e}")

    # Detach policy from group
    print("Detaching policy from group...")
    try:
        iam_client.detach_group_policy(GroupName=GROUP_NAME, PolicyArn=policy_arn)
    except ClientError as e:
        if e.response['Error']['Code'] != 'NoSuchEntity':
            print(f"Error detaching policy from group: {e}")

    # Delete policy
    print("Deleting policy...")
    try:
        iam_client.delete_policy(PolicyArn=policy_arn)
    except ClientError as e:
        if e.response['Error']['Code'] != 'NoSuchEntity':
            print(f"Error deleting policy: {e}")

    # Delete group
    print("Deleting group...")
    try:
        iam_client.delete_group(GroupName=GROUP_NAME)
    except ClientError as e:
        if e.response['Error']['Code'] != 'NoSuchEntity':
            print(f"Error deleting group: {e}")

    # Delete user
    print("Deleting user...")
    try:
        iam_client.delete_user(UserName=USER_NAME)
    except ClientError as e:
        if e.response['Error']['Code'] != 'NoSuchEntity':
            print(f"Error deleting user: {e}")

    print("\n--- All IAM resources cleaned up successfully ---")

def main():
    policy_arn = None
    try:
        create_iam_user()
        create_iam_group()
        policy_arn = create_iam_policy()
        attach_policy_to_group(policy_arn)
        add_user_to_group()

        print("\n--- IAM setup complete. User has S3 read-only access via group. ---")
        input("Press Enter to clean up resources...")

    except ClientError as e:
        print(f"An AWS client error occurred: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
    finally:
        if policy_arn:
            cleanup_resources(policy_arn)

if __name__ == "__main__":
    main()
