AWS Security Blog

AWS CloudTrail Now Tracks Cross-Account Activity to Its Origin

You can use AWS Identity and Access Management (IAM) roles and AWS Security Token Service (STS) to set up cross-account access between AWS accounts. When you assume an IAM role in another AWS account to obtain cross-account access to services and resources in that account, AWS CloudTrail logs the cross-account activity. Starting today, CloudTrail logs AssumeRole calls in the role-owning account (the account being accessed), including the unique ID of the IAM entity (a user or role) assuming the role in the account being accessed. This additional information helps you identify the entity that requested cross-account access and then trace its subsequent cross-account activity.

In this blog post, I show how you can use the new AssumeRole log file in the role owner’s account to trace unexpected cross-account activity to its origin.

Example of AWS cross-account AWS access

Before I get into the walkthrough, let’s briefly review the basics of AWS cross-account access. The following diagram shows a typical cross-account access scenario.

In this diagram, IAM user Alice in the Dev account (the role-assuming account) needs to access the Prod account (the role-owning account). Here’s how it works:

  1. Alice in the Dev account assumes an IAM role (WriteAccess) in the Prod account by calling AssumeRole.
  2. STS returns a set of temporary security credentials.
  3. Alice uses the temporary security credentials to access services and resources in the Prod account. Alice could, for example, make calls to Amazon S3 and Amazon EC2, which are granted by the WriteAccess role.

With the new CloudTrail logging behavior, you can look in the CloudTrail bucket of the role-owning account (Prod account) and see a log file of the AssumeRole call. Previously, CloudTrail only logged this in the role-assuming account (Dev account).

How do I use the new log?

Let’s walk through an example of how to trace cross-account actions back to the user or role that initiated cross-account access (note that the new logging behavior appears in Step 2 below). In this walkthrough, I show how a security administrator who notices unusual cross-account activity can trace it back to its origin.

Note: This walkthrough assumes that the administrator has access to both AWS accounts involved in the cross-account activity, which is a common use case. However, if you granted cross-account access to a third-party AWS account (such as a business partner or an ISV’s SaaS product), tracing cross-account activity back to an account that you don’t own requires voluntary participation from the third party.

Step 1: In the role-owning account, identify the cross-account action you want to investigate
The security administrator notices that someone has deleted an S3 bucket in the Prod account that no user or role should delete. The administrator looks in CloudTrail and finds the following log file of the S3 DeleteBucket action. It shows that AssumedRole credentials were used for the DeleteBucket action, which indicates that this could have been cross-account activity. Note that AssumedRole credentials don’t necessarily mean that activity was cross-account—users or roles in the same account can also assume a role.

The administrator now wants to know who assumed this IAM role used to make this request and proceeds to search their logs for an AssumeRole event with a matching accessKeyId (highlighted in the following userIdentity block).

{
    "eventVersion": "1.04",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROAIDPPEZS35WEXAMPLE:AliceSession",
        "arn": "arn:aws:sts::111122223333:assumed-role/WriteAccess/AliceSession",
        "accountId": "111122223333",
        "accessKeyId": "ASIAIVOTP66PNEXAMPLE",
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2016-11-14T17:25:26Z"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAIDPPEZS35WEXAMPLE",
                "arn": "arn:aws:iam::111122223333:role/WriteAccess",
                "accountId": "111122223333",
                "userName": "WriteAccess"
            }
        }
    },
    "eventTime": "2016-11-14T17:25:45Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "DeleteBucket",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "72.21.198.66",
    "userAgent": "[aws-cli/1.11.10 Python/2.7.8 Linux/3.2.45-0.6.wd.865.49.315.metal1.x86_64 botocore/1.4.67]",
    "requestParameters": {
        "bucketName": "ProdAccountExampleBucket"
    },
    "responseElements": null,
    "requestID": "10B2252463D56D4C",
    "eventID": "42493e77-75e5-41fa-a2e1-766555c30611",
    "eventType": "AwsApiCall",
    "recipientAccountId": "111122223333"
}

Step 2: In the role-owning account, identify the AssumeRole event that provided credentials used for the action
The administrator searches the Prod account’s CloudTrail logs and finds the log file of the AssumeRole API call that yielded the temporary security credentials used for the action in question (see the following log). This is the new CloudTrail log type available with today’s release. The log record includes who assumed the role, when the role was assumed, the credentials that were returned by the AssumeRole call, and other metadata (all of which was previously logged only in the role assumer’s account).

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSAccount",
        "principalId": "AIDAJ45Q7YFFAREXAMPLE",
        "accountId": "123456789012"
    },
    "eventTime": "2016-11-14T17:25:26Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "72.21.198.66",
    "userAgent": "aws-cli/1.11.10 Python/2.7.8 Linux/3.2.45-0.6.wd.865.49.315.metal1.x86_64 botocore/1.4.67",
    "requestParameters": {
        "roleArn": "arn:aws:iam::111122223333:role/WriteAccess",
        "roleSessionName": "AliceSession"
    },
    "responseElements": {
        "credentials": {
            "accessKeyId": "ASIAIVOTP66PNEXAMPLE",
            "expiration": "Nov 14, 2016 6:25:26 PM",
            "sessionToken": "<encoded_session_token_blob>"
        },
        "assumedRoleUser": {
            "assumedRoleId": "AROAIDPPEZS35WEXAMPLE:AliceSession",
            "arn": "arn:aws:sts::111122223333:assumed-role/WriteAccess/AliceSession"
        }
    },
    "requestID": "54ead46a-aa8f-11e6-bb4e-dd0a0d824ead",
    "eventID": "b590c927-3148-4d8e-ad7c-8d516fdae801",
    "resources": [
        {
            "ARN": "arn:aws:iam::111122223333:role/WriteAccess",
            "accountId": "111122223333",
            "type": "AWS::IAM::Role"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "111122223333",
    "sharedEventID": "9fe2fddd-a338-4380-b64d-ca74b7b828e5"
}

In this new log:

  • The green-highlighted userIdentity block contains the principalId of the IAM user or IAM role in the Dev account that called AssumeRole.
  • The yellow-highlighted accessKeyId contains the temporary access key ID returned by the AssumeRole call (note that CloudTrail omits the temporary secret key).
  • The blue-highlighted sharedEventID connects this AssumeRole log file in the role-owning account to the corresponding AssumeRole log file in the role-assuming account.

The administrator uses this temporary accessKeyId to correlate this initial AssumeRole call with subsequent cross-account activity identified in Step 1. If the administrator comes across more log files in the Prod account with a matching accessKeyId, the administrator knows that the same principalId made those API calls using temporary security credentials obtained from this AssumeRole call.

Now the administrator is ready to identify the entity in the Dev account responsible for deleting the S3 bucket in the Prod account.

Step 3: In the role-assuming account, find a matching AssumeRole event that identifies the original caller
The administrator refers to the sharedEventID value from the preceding example log to identify the original role assumer. The administrator searches in the Dev account’s CloudTrail logs for an AssumeRole log file with the same sharedEventID. When the administrator finds the corresponding AssumeRole event (see the following log for an example), she looks at the the userIdentity block to learn more details about the caller, including the friendly name of the IAM user or IAM role, and its Amazon Resource Name (ARN).

In this case, the administrator discovers that an IAM user named Alice in the Dev account (123456789012) was responsible for deleting the S3 bucket in the Prod account (111122223333).

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "AIDAJ45Q7YFFAREXAMPLE",
        "arn": "arn:aws:iam::123456789012:user/Alice",
        "accountId": "123456789012",
        "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
        "userName": "Alice"
    },
    "eventTime": "2016-11-14T17:25:26Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "72.21.198.66",
    "userAgent": "aws-cli/1.11.10 Python/2.7.8 Linux/3.2.45-0.6.wd.865.49.315.metal1.x86_64 botocore/1.4.67",
    "requestParameters": {
        "roleArn": "arn:aws:iam::111122223333:role/WriteAccess",
        "roleSessionName": "AliceSession"
    },
    "responseElements": {
        "credentials": {
            "accessKeyId": "ASIAIVOTP66PNEXAMPLE",
            "expiration": "Nov 14, 2016 6:25:26 PM",
            "sessionToken": "<encoded_session_token_blob>"
        },
        "assumedRoleUser": {
            "assumedRoleId": "AROAIDPPEZS35WEXAMPLE:AliceSession",
            "arn": "arn:aws:sts::111122223333:assumed-role/WriteAccess/AliceSession"
        }
    },
    "requestID": "54ead46a-aa8f-11e6-bb4e-dd0a0d824ead",
    "eventID": "cf1929cf-7123-4186-b85d-791c9d0974a9",
    "resources": [
        {
            "ARN": "arn:aws:iam::111122223333:role/WriteAccess",
            "accountId": "111122223333",
            "type": "AWS::IAM::Role"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "123456789012",
    "sharedEventID": "9fe2fddd-a338-4380-b64d-ca74b7b828e5"
}

The AWS Security Blog published a blog post earlier this year about a solution for auditing cross-account activity that uses CloudTrail, Amazon CloudWatch Events, and AWS Lambda. This automated log-tracing solution works with the new logging behavior made available today.

To learn more about STS logging, see the IAM user guide. If you have comments about auditing cross-account activity or this blog post, start a new thread in the IAM forum.

– Kai