# Keep track of AWS user activity with SourceIdentity attribute


The `SourceIdentity` attribute in AWS’s Security Token Service (STS) can help defenders trace AWS role activity back to its source.

As we have discussed [**previously**](https://redcanary.com/blog/threat-detection/aws-sts/), adversaries who gain access to AWS accounts can abuse the Security Token Service (STS) to grant themselves short-term tokens and assume roles before performing malicious activity within that cloud environment. Historically, the main way to attribute activity performed by a user after they have assumed a role was to [**track access keys**](https://aws.amazon.com/blogs/security/how-to-audit-cross-account-roles-using-aws-cloudtrail-and-amazon-cloudwatch-events/) every time a user assumed a new role. While this can work, there are also known [**workarounds**](https://www.gem.security/post/aws-console-session-traceability-how-attackers-obfuscate-identity-through-the-aws-console) to obfuscate activity and break the trail of access keys, making it difficult to trace activity back to the compromised user account.

However, AWS has an [**attribute in STS**](https://aws.amazon.com/blogs/security/how-to-relate-iam-role-activity-to-corporate-identity/) called `SourceIdentity` that allows defenders to trace all user activity in `AssumeRole` sessions back to corporate identities such as usernames or email addresses.

## **What is** `SourceIdentity`?

So, what is this `SourceIdentity` attribute and what does it do for you? It allows you to require a field whenever a user assumes a role in AWS that is akin to role session name or session tags. `SourceIdentity` stands apart from these other fields by the fact that it persists throughout all follow-on sessions the user creates. If they were to assume one role and then pivot to another, `SourceIdentity` would persist in the logs even if they didn’t specify it in the subsequent `AssumeRole` calls.

As with most fields in AWS, you can also specify `SourceIdentity` to be a specific value. When you configure the trust relationships for the roles, you can specify that `SourceIdentity` must be a username, email address, or any other identifier. You can also integrate it with your identity providers such as Okta, Ping, or OneLogin.

> `SourceIdentity` stands apart from other AWS attributes by the fact that it persists throughout all follow-on sessions the user creates.

## `SourceIdentity` in action

For this exercise, we will follow the user `accessKeyIdTesting` through two`AssumeRole` calls and finally their execution of the `GetCallerIdentity` API event. The screenshot below outlines the basic steps of the process.

![Tracking the username "accessKeyIdTesting" through various role changes using the AWS's SourceIdentity attribute](https://redcanary.com/wp-content/uploads/2024/09/image2.png align="center")

So what does that look like in the logs?

### First `AssumeRole` event

```html
aws sts assume-role --role-arn arn:aws:iam::<accountId>:role/accessKeyIdTesting --role-session-name sourceTesting --source-identity followMe  --profile accessKeyTesting
```

The first event is the original `AssumeRole`, wherein we specify the `SourceIdentity` field as `followMe`. Normally you would want to set the condition that this field is some sort of corporate identity such as an email address or username.

Since we specified the `SourceIdentity` in the `AssumeRole` request, we can observe it in both the `responseElements` and the `requestParameters`. Since this is the original `AssumeRole` event, it is not present in the `userIdentity` field (keep this in mind for later).

![The SourceIdentity attribute shows up in both the requestParameters and the responseElements fields. ](https://redcanary.com/wp-content/uploads/2024/09/image3.png align="left")

*Figure 1:* `AssumeRole` event with `SourceIdentity`

In Figure 1 we can see that the new `SourceIdentity` field is present in both the `requestParameters` and the `responseElements`. The `responseElements` section should be the only one used to track `SourceIdentity` as it will always be present even if it is not part of the original request, as will be evident in the next event.

### `AssumeRole` chain

```html
aws sts assume-role --role-arn arn:aws:iam::<accountId>:role/lambdaManager --role-session-name sourceTesting  --profile sourceIdenRole
```

The user then pivots to another role from the first one without specifying `SourceIdentity`. In the logs, even though it wasn’t specified, it still shows up in the `responseElements`! This makes it so much easier to track what the user is doing during their entire session. Previously, you’d have to track the access keys and capture that for each pivot to the new role.

![the SourceIdentity field is present under the userIdentity.sessionContext field and matches the value from the responseElement in Figure 1](https://redcanary.com/wp-content/uploads/2024/09/image4.png align="left")

*Figure 2:* `AssumeRole userIdentity` elements

In Figure 2 above we can see that the `SourceIdentity` field is present under the `userIdentity.sessionContext` field and matches the value from the `responseElement` in Figure 1. This allows us to trace the activity of the two events.

![The SourceIdentity attribute is still present in the responseElements field after the second AssumeRole call.](https://redcanary.com/wp-content/uploads/2024/09/image5.png align="left")

*Figure 3:* `AssumeRole` part deux `responseElements`

In Figure 3 we can see that with this new `AssumeRole` call, the `SourceIdentity` was not specified in the command and therefore not included in the `requestParameters`. However, since it was included in the first call it is still supplied in the `responseElements`.

### The API call

Finally, the user then in this final role executes the `GetCallerIdentity` command. In the CloudTrail event we can clearly see the `SourceIdentity` field in `userIdentity` parameters. We can trace this back to that specific user regardless of what roles they have assumed or what events they execute.

![Using the GetCallerIdentity call to trace the API call back to its original source ](https://redcanary.com/wp-content/uploads/2024/09/image1-1.png align="left")

*Figure 4:* `GetCallerIdentity`

As was true with the second `AssumeRole` call, the `SourceIdentity` field exists in the `userIdentity.sessionContext` field. This allows us to trace back this activity from the API call all the way back to the `AssumeRole` call without having to rely on access keys. It will also allow us to just directly tie this API call to whichever user identifier we choose when we configure `SourceIdentity` to be required for all users.

## **So what?**

Why is this attribute so helpful? Users may leverage several different roles while using services in AWS, and tracking who is doing what can be near impossible with medium-to-large AWS accounts. `SourceIdentity` allows defenders to baseline “normal” activity more easily. We don’t have to rely on temporary and random credential identifiers to track sessions anymore; `SourceIdentity` takes care of that for us.

With `SourceIdentity` we can simply compare anomalous behavior to previous sessions to make a determination if it is malicious or not. Determining what constitutes “normal” behavior is almost impossible in cloud environments unless admins have strict security policies and well named, very descriptive roles. We know that this will not always be the case, and enabling `SourceIdentity` will enable defenders to make determinations with significantly more confidence.
