Skip to content

How to Monitor and Respond to Unauthorized Security Profile Assignments in Amazon Connect?

0

We're using Amazon Connect without IAM integration or SAML implementation due to legacy system constraints. We need a solution to monitor and automatically respond to situations where unauthorized users attempt to assign elevated security profiles to themselves or others within our Amazon Connect environment. What's the best way to implement this using AWS services? We're looking for a solution that can detect these attempts, revert unauthorized changes, and notify our security team.

5 Answers
0

To monitor and respond to unauthorized security profile assignments in Amazon Connect without IAM integration or SAML implementation, you can use a combination of AWS services. Here's a detailed solution:

  1. Amazon EventBridge: Set up an EventBridge rule to monitor Amazon Connect UpdateUserSecurityProfiles and CreateUser events. Use the following event pattern:

    {
      "source": ["aws.connect"],
      "detail-type": ["AWS API Call via CloudTrail"],
      "detail": {
        "eventSource": ["connect.amazonaws.com"],
        "eventName": ["UpdateUserSecurityProfiles", "CreateUser"]
      }
    }
  2. AWS Lambda Function: Create a Lambda function triggered by the EventBridge rule. This function will:

    • Check if the event is initiated by an authorized user or the Lambda itself.
    • Revert unauthorized elevated security profile assignments.
    • Send alerts via Amazon SNS.
    • Log detailed information for auditing.
  3. Amazon SNS: Set up an SNS topic to send notifications to your security team.

  4. IAM Role for Lambda: Create an IAM role for the Lambda function with the following permissions:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "connect:DescribeUser",
            "connect:UpdateUserSecurityProfiles"
          ],
          "Resource": [
            "arn:aws:connect:REGION:ACCOUNT_ID:instance/INSTANCE_ID/agent/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
            "connect:UpdateUserSecurityProfiles"
          ],
          "Resource": [
            "arn:aws:connect:REGION:ACCOUNT_ID:instance/INSTANCE_ID/security-profile/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
            "logs:CreateLogStream",
            "logs:CreateLogGroup",
            "logs:PutLogEvents"
          ],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "sns:Publish"
          ],
          "Resource": [
            "arn:aws:sns:REGION:ACCOUNT_ID:TOPIC_NAME"
          ]
        }
      ]
    }
  5. Lambda Function Code: Here's a Python script for the Lambda function:

    import json
    import boto3
    import os
    import logging
    import urllib.parse
    
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    sns_client = boto3.client('sns')
    connect_client = boto3.client('connect')
    
    def get_user_name(instance_id, user_id):
        try:
            response = connect_client.describe_user(InstanceId=instance_id, UserId=user_id)
            user_info = response.get('User')
            if user_info:
                return user_info.get('Username')
        except Exception as e:
            logger.error(f"Error retrieving user name: {str(e)}")
            return None
    
    def get_instance_id_from_arn(instance_arn):
        parts = instance_arn.split('/')
        return parts[-1] if parts else None
    
    def lambda_handler(event, context):
        security_profile_ids_to_check = [id.strip() for id in os.environ['ADMIN_SECURITY_IDS'].split(',')]
        admin_ids = [id.strip() for id in os.environ['AUTHORIZED_IDS'].split(',')]
        dummy_security_profile_id = os.environ['DUMMY_SECURITY_PROFILE_ID'].strip()
        lambda_name = os.environ['LAMBDA_NAME'].strip()
        sns_topic_arn = os.environ['SNS_TOPIC_ARN'].strip()
    
        try:
            details = event.get('detail')
            logger.info(details)
            if details and details['eventName'] in ['UpdateUserSecurityProfiles', 'CreateUser']:
                principal_id = details.get('userIdentity', {}).get('principalId')
                user_key = principal_id.split(':')[1] if principal_id and ':' in principal_id else None
                logger.info(f"Principal Id: {user_key}")
                if not user_key == lambda_name:
                    encoded_instance_arn = details.get('requestParameters', {}).get('InstanceId')
                    instance_arn = urllib.parse.unquote(encoded_instance_arn)
                    instance_id = get_instance_id_from_arn(instance_arn)
                    principal_user = connect_client.describe_user(
                        UserId=user_key,
                        InstanceId=instance_id
                    )
                    principal_username = principal_user.get("User", {}).get("Username")
                    logger.info(f"Principal username: {principal_username}")
                    if user_key not in admin_ids:
                        logger.info(f"Principal Id {user_key} is not in the list of admin IDs. Processing event.")
                        user_id = (details.get('responseElements', {}).get('UserId')) if details['eventName'] == 'CreateUser' else (details.get('requestParameters', {}).get('UserId'))
                        security_profile_ids = details.get('requestParameters', {}).get('SecurityProfileIds', [])
                        if any(id in security_profile_ids for id in security_profile_ids_to_check):
                            user_name = get_user_name(instance_id, user_id)
                            logger.info(f"Admin security profile assigned to user {user_name}.")
                            sns_client.publish(
                                TopicArn=sns_topic_arn,
                                Message=f"Admin security profile has been assigned to user {user_name} by {principal_username}. Removing privileged profiles and assigning Dummy profile to the user.",
                                Subject="Alert: Admin Profile Assigned"
                            )
                            updated_profile = [dummy_security_profile_id]
                            logger.info("Ready to update the security profile to a dummy security profile!")
                            connect_client.update_user_security_profiles(
                                UserId=user_id,
                                InstanceId=instance_id,
                                SecurityProfileIds=updated_profile
                            )
                    else:
                        logger.info(f"Principal ID {user_key} is in the list of admin IDs. Skipping action.")
                else:
                    logger.info(f"Principal ID {user_key} is the lambda function. Skipping action.")
            else:
                logger.info("Event is not related to security profile updates or no details found.")
        except Exception as e:
            logger.error(f"Error processing event: {str(e)}")
            raise e
    
        return {
            'statusCode': 200,
            'body': json.dumps('Event processed')
        }
  6. Configuration: Set the following environment variables for the Lambda function:

    • ADMIN_SECURITY_IDS: Comma-separated list of security profile IDs to monitor
    • AUTHORIZED_IDS: Comma-separated list of authorized user IDs
    • DUMMY_SECURITY_PROFILE_ID: ID of the dummy security profile to assign
    • LAMBDA_NAME: Name of the Lambda function
    • SNS_TOPIC_ARN: ARN of the SNS topic for notifications
  7. Implementation Steps: a. Create the SNS topic for notifications. b. Set up the IAM role for the Lambda function with the provided policy. c. Create the Lambda function using the provided Python code and configure the environment variables. d. Create the EventBridge rule with the specified event pattern and set the Lambda function as the target. e. Test the setup by attempting to assign an admin security profile to a non-authorized user.

  8. Monitoring and Maintenance:

    • Regularly review the CloudWatch logs for the Lambda function to ensure it's working correctly.
    • Periodically update the list of authorized users and admin security profile IDs as needed.
    • Consider implementing a rotation mechanism for the dummy security profile to enhance security.
  9. Best Practices and Considerations:

    • Regularly audit and review the list of authorized users who can assign admin security profiles.
    • Implement proper error handling and retry mechanisms in the Lambda function to ensure reliability.
    • Consider implementing additional logging and monitoring to track all security profile changes, even those made by authorized users.
    • Regularly review and update the dummy security profile to ensure it has minimal permissions necessary for basic operations.
  10. Limitations and Future Improvements:

    • This solution doesn't prevent initial assignment of elevated privileges but reverts them quickly.
    • Consider implementing rate limiting to prevent potential abuse of the system.
    • For a more robust long-term solution, plan to migrate to IAM integration or SAML implementation for Amazon Connect.

By implementing this solution, you'll have a monitoring and response system in place to detect and revert unauthorized security profile assignments in your Amazon Connect environment. This helps mitigate the risk of unauthorized access and potential security breaches, even without IAM integration or SAML implementation.

Remember that while this solution provides an additional layer of security, it's still crucial to work towards implementing the recommended best practices for user management and access control in Amazon Connect as soon as possible. This includes integrating with IAM or implementing SAML for more robust and scalable security.

Lastly, ensure that you have proper change management processes in place when implementing this solution, and thoroughly test it in a non-production environment before deploying to your production Amazon Connect instance.

AWS
EXPERT
answered a year ago
0

I see you answered your own question, but would you please clarify what you mean by not being integrated with IAM? In your Python code, you're identifying the user who performed the action as either being or not being a trusted administrator based on userIdentity.principalId, which appears to be expected to contain the ID of the role the user is acting under, followed by some form of user identifier you're parsing into the user_key variable.

This means you are integrated with AWS IAM, so I assume you mean some corporate identity and access management solution by the IAM that you mentioned not being integrated with.

In the case of an assumed role session, the same value you're extracting from userIdentity.principalId is available in the global IAM condition key aws:userid, which you can use in all AWS access policies that support global condition keys. Instead of first granting people the permission to do what they shouldn't, then scanning logs for violations, and running and maintaining a custom script to try to reverse the damage, is there a reason why you wouldn't simply restrict the permissions to allow only what users are allowed to do?

In access policies, both the connect:CreateUser permission (https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonconnect.html#amazonconnect-CreateUser) and connect:UpdateUserSecurityProfiles (https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonconnect.html#amazonconnect-UpdateUserSecurityProfiles) allow targeting the permissions based on both security profile ARN and Connect user ARN.

When you combine these two capabilities, you could identify the acting user with a StringEquals or StringLike comparison based on aws:userid, and limit the CreateUser and UpdateUserSecurityProfiles actions for regular users to permit only those security profiles that they are supposed to be assigning. Both the StringEquals and StringLike operators (and their negated variants) accept multiple values to compare in arrays, so a single policy statement can apply to several users and/or security profiles.

If your users are logging on as IAM users, followed by them assuming an IAM role, a much cleaner solution would be to have separate roles for the administrator and non-administrator users. For each role, you'd create a managed IAM policy that allows assuming the specific role, and attach that policy to a matching IAM user group. Finally, add the administrator users to the IAM user group for administrators and the rest to the non-administator group.

This way, the aws:userid condition key would no longer be needed, because the IAM policies attached to the IAM user groups would control which user can assume which role, and which security profiles each of the roles could attach Amazon Connect users to would be controlled by the identity-based IAM policies attached to the roles.

In both cases, you could still use your CloudTrail-based monitoring to detect attempts to break the rules, if you'd like, but disallowed configurations would never take effect even momentarily, until the events got delivered by CloudTrail, processed by the Lambda function, and the reversals processed and propagated. Your monitoring logic could be greatly simplified by simply listening for events with an AccessDenied error code for the CreateUser and UpdateUserSecurityProfiles actions, rather than having to maintain the logic to evaluate the specific the profile IDs and usernames in custom code.

EXPERT
answered a year ago
0

Hi Leo. Thank you for your detailed feedback. I need to clarify an important point: The solution I proposed is specifically for Amazon Connect environments where users are created directly in Connect without IAM or SAML integration. While the Lambda function does use IAM (as you correctly pointed out) for its own execution, the users we're monitoring are native Connect users, not IAM users.

In Amazon Connect, it's possible to create users directly in the Connect console without any IAM association. In these scenarios:

  1. Users authenticate directly to Connect, not through IAM
  2. IAM policies cannot control their actions within Connect
  3. Security profiles are the only way to control permissions
  4. There's no way to preventively restrict security profile assignments using IAM policies

This is why the solution takes a detective and reactive approach rather than a preventive one. While your suggested approach using IAM policies would indeed be more elegant and secure, it's unfortunately not applicable in environments where Connect users are managed independently of IAM.

The use of principalId in the code is primarily to identify the Lambda's own actions to prevent recursive updates, rather than for IAM-based access control.

Would a preventive IAM-based solution be better? Absolutely. However, for organizations that haven't implemented IAM integration or SAML with Connect (often due to legacy setups or specific business requirements), this solution provides a way to monitor and respond to unauthorized security profile changes.

AWS
EXPERT
answered a year ago
0

Hi kariibha. Your solution listens to UpdateUserSecurityProfiles and CreateUser API calls from CloudTrail and extracts the part of the userIdentity.principalId element in the event following the first colon : to identify the user. Even when the Connect service executes an API call on behalf of the user who logged in with credentials internal to Connect (and not with IAM credentials), the service has to authenticate to the API and go through the IAM authorisation process.

Based on your code, it looks like the events you're catching are made under an IAM role, even if it the role has been assumed by the Connect service and not directly by your users. The same information that is recorded in the CloudTrail event's userIdentity.principalId element should be present in the aws:userid condition key in the request context. With the exception of service-linked roles (SLRs), all actions requiring authorisation taken by IAM roles can be restricted in various ways, such as by attaching policies with "deny" statements to the role, specifying a permissions boundary for the role, or applying an SCP to the AWS account.

What are you seeing contained in the userIdentity.principalId element when users make changes they shouldn't be making? Is the value perhaps something like AROADBQP57FF2AEXAMPLE:connectuser, where "connectuser" would be the username with which they logged on to the Connect service (and not to IAM)?

EXPERT
answered a year ago
0

Looking at the documentation for security profiles in Connect, there also appears to be a mechanism to achieve your goal of restricting agents from assigning overly permissive security profiles with mechanisms internal to Connect, without involving AWS IAM.

This documentation section: https://docs.aws.amazon.com/connect/latest/adminguide/tag-based-access-control.html#tag-based-access-control-connect-ui explains that you could tag the non-admin users in Connect with a tag, such as Department:Agents. You would also tag the security groups that they are allowed to attach with the same tag.

Once all the appropriate users and security groups have been tagged, create a security profile that you will assign to the agent users responsible for managing users in Connect. Specify the Department:Agents tag as the value for the --allowed-access-control-tags parameter (https://awscli.amazonaws.com/v2/documentation/api/latest/reference/connect/create-security-profile.html), and specify both User and SecurityProfile as values to the --tag-restricted-resources parameter.

This should cause all the agents assigned this profile only to be able to see entities of the types User and SecurityProfile that have the tag Department:Agents specified. Even though they would have the permission to manage users, the tag-based restriction would prevent them from creating a user with an overly permissive security profile or from resetting the password of an existing user with admin privileges.

When creating new users, your agents would need to add the Department:Agents tag also to all the new users they create, so that the newly created users remain visible to them.

EXPERT
answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.