Using External ID with AWS IAM Roles

At times, you might want to hire third party AWS partners/service providers to manage your AWS infrastructure. They eventually need to take a look at your AWS resources and execute API operations that list, describe, create or update components in your AWS account.
There are multiple ways to set up cross-account access but the most popular and secure one is using roles.
With IAM roles, you can grant these third parties access to your AWS resources without sharing your AWS security credentials. Instead, the third party can access your AWS resources by assuming a role that you create in your AWS account.
Conventionally, roles are created by defining a trust policy and a permissions policy for the third party and granting the role ARN to it so that it can assume that role using the AssumeRole API.
But it is important to take into account the fact that the service provider has many customers that it manages and it might be possible for one of customers to guess the role ARN of any other customer. Role ARNs are of a fixed format and typically easier to crack. That customer could then use the other customer’s role ARN to gain access to its AWS resources by way of the service provider. This form of privilege escalation is known as the “Confused Deputy Problem”.
The above problem can be better explained with the help of an example:

Consider a scenario where you decide to hire a third-party company called Example Corp to monitor and manage your AWS infrastructure. In order to track your resources Example Corp needs to access your AWS resources. Example Corp also monitors many other AWS accounts for other customers.
Typically, you use an IAM role to establish a trusted relationship between your AWS account and the Example Corp account. Example Corp also monitors many other AWS accounts for other customers.
In the above diagram, consider:
AWS1 is your AWS account.
AWS1:ExampleRole is a role in your account.
Example Corp manages another AWS account as well, as shown in the diagram.
Here’s a detailed breakdown of what can happen:
1) You create a role named AWS1:ExampleRole for Example Corp with the relevant permissions attached to it and provide the role ARN to it.
2) Example Corp assumes that role using the AssumeRole API to access your AWS resources.
3) Another AWS customer also starts using Example Corp’s service, and this customer also provides the ARN of AWS1:ExampleRole for Example Corp to use. Presumably the other customer learned or guessed the AWS1:ExampleRole, which isn’t a secret.
4) When the other customer asks Example Corp to access AWS resources in (what it claims to be) its account, Example Corp uses AWS1:ExampleRole to access resources in your account.
This is how the other customer could gain unauthorized access to your resources. Because this other customer was able to trick Example Corp into unwittingly acting on your resources, Example Corp is now a “confused deputy.”
Thus, to overcome this scenario, you should use an additional layer of security in the form of External ID.
External ID is an optional piece of information that you can use in an IAM role trust policy to designate who can assume the role. In abstract terms, the external ID allows the user that is assuming the role to assert the circumstances in which they are operating. It also provides a way for the account owner to permit the role to be assumed only under specific circumstances.
The primary function of the external ID is to address and prevent the “confused deputy” problem.
The external ID can be any secret identifier that is known by you and the third party and must be unique for all its customers.
While creating the role, ask the third party for an external ID and include it in the trust policy of the role as shown below:
{
  “Version”: “2012-10-17”,
  “Statement”: {
    “Effect”: “Allow”,
    “Action”: “sts:AssumeRole”,
    “Principal”: {“AWS”: “Third party’s AWS Account ID”},
    “Condition”: {“StringEquals”: {“sts:ExternalId”: “12345”}}
  }
}
The Condition element in this policy allows the service provider to assume the role only when the AssumeRole API call includes the external ID value of “12345”.
In other words, when a role policy includes an external ID, anyone who wants to assume the role must be a principal in the role and must include the correct external ID in the AssumeRole API call.
In this way, the third-party service provider helps its customers to do the right thing, which helps to keep the both of them protected against the confused deputy problem.
Thus, it is always a recommended approach to use external ID along with roles to keep the unauthorized access to your resources in check.
Contributed by : Nikita Punjabi
https://www.linkedin.com/in/nikita-p-221406162/