This is the second post of our series that summarise the most common security issues in AWS. In the first part we took an in-depth look at the AWS Lambda responsibility model.
In this post I’m going to talk about AWS IAM cross account trusts and how they can be used to gain an initial foothold or persistence to an AWS Account.
Cross account trusts are the recommended method of giving a third-party entity — we’ll call them suppliers from now on — access to your AWS account.
Finally, I’ll introduce you to AWSXenos, a tool that I wrote that can help you identify, and reason about IAM Role and resource cross account trusts.
GitHub – Airwalk-Digital/AWSXenos: AWSXenos will list all the trust relationships in all the IAM roles, and S3 buckets, in an AWS account and give you a breakdown of all the accounts that have trust relationships to your account.
The recommended way of giving a supplier access to your AWS account is via a cross account trust, on an AWS Role. You don’t have to manage credentials and you can explicitly allow access to another AWS IAM identity. In the AWS documentation this is referred to as an Assume Role Policy Document or a trust policy. Technically this is a single API call to the AWS Security Token Service (STS), which returns a pair of time bound credentials, for the target role. For those curious on how the AWS STS AssumeRole works, this is what an example request looks like.
From a security and operational standpoint, this is a lot better, and preferred to handling AWS User credentials. You don’t have to distribute, and manage credentials. AWS manages the whole thing on your and the supplier’s behalf.
All in all, you’ll need to provide a Valid Account to a supplier to access your AWS resources or their configuration. You’re probably already doing this if you’re integrating with almost any supplier in the areas of:
Operating a workload, almost always requires establishing a cross account trust. Either from a supplier, from within your AWS Organization, or from an AWS service account.
A cross account trust without any effective permissions attached to the role can be benign. However, although most suppliers including AWS, tend to offer a least privilege permissions policy, the responsibility falls under the AWS account owner:, you. This is crucial when setting up a cross account trust. There are numerous ways of accomplishing privilege escalation when inside an AWS Account.
Integrating with dozens of suppliers on an AWS account, is a daily occurrence for a lot of cloud-mature organisations. Offboarding however is a different matter. Does your organisation revoke all trusts and sessions, across your estate, once a contract with a supplier comes to an end ?
Detection and continuous compliance
The way a cross account trust is configured, there is no easy way to discern whether this is a supplier, a typo on the account ID, or someone who has created a backdoor to the AWS account. Endgame is a great example of automating the exploitation of this cross account trust and exposing roles or other resources, effectively giving an adversary persistent access to the AWS account. The problem has a different dimension when it comes to resource policies. Being able to lock down a resource — e.g. an S3 bucket — only to your AWS Account or AWS Organization. The key takeaway here is that you should know all the cross account trusts across your estate, at all times.
Even from within your AWS Organization, cross account trusts originating from a known IAM identity, can be problematic. Look at the following AWS landing zone diagram from the AWS Solution implementation page.
There’s another hidden dimension to this diagram, environments. Do you have a shared services account for all your production, and sandbox accounts ? Is your CI/CD using a hub & spoke pattern across different environments?
Depending on the workload, regulatory, architectural, and security requirements, this might not be ideal. What is certain, is that you’d always want to have visibility of the cross account trust.
Supply Chain Attacks
Theoretically as an adversary, any supplier’s AWS account is a prime target. There are two main avenues for an adversary to compromise a cross account trust relationship. The first avenue is by exploiting the confused deputy problem.
Role ARNs are not secrets. A supplier — the deputy — will be able to assume roles in both Bob’s and Alice’s AWS Accounts. If Alice knows the Role ARN that Bob uses with the supplier, Alice can trick the supplier by giving that Role ARN as one of her own.
If the supplier does not provide you with a unique External ID, as part of the condition of the IAM trust policy, then another AWS Account can provide a valid Role ARN from your AWS Account. This way they’ll have access to your resources, via the supplier’s integration. AWS IAM documentation covers the confused deputy problem extensively.
Of note is that AssumeRole calls, will not show up in the target account’s CloudTrail, unless the call is successful, i.e. you will not know that someone is trying to guess a Role ARN that can be assumed externally, until they have successfully assumed the role.
The second avenue is via a supplier compromise. An adversary with access to the supplier’s AWS Account, will have a direct valid account to every one of their customers’ AWS accounts. And you would have no easy way of knowing whether this compromise has happened in the first place, unlike other types of supply chain attacks. The extent of what an adversary can do, is subject to the permissions and the nature of the integration that you have with the supplier.
IAM Access Analyzer is great, it has a fairly comprehensive coverage of resource policies. It will detect cross account role trusts but falls short because:
You need to enable it in every region for all account resources — might not be a problem if you have a Landing Zone pattern that can cater for this.
Identified external entities might be known entities. E.g. a trusted third party supplier or a supplier you no longer do business with. An AWS Account number is seldom useful.
Zone of trust is a fixed set of the AWS organisation. You won’t know if a trust between sandbox->prod has been established. It would be beneficial to be able to set zones of trust within Organizational OUs.
We need to take this a step further, and understand:
Do we know the account in the first place?
Can we classify the relationship between the two accounts?
To answer the first question, AWSXenos will query the AWS Organization and a set of known AWS Account IDs. If the Account ID, matches any of these, then this is an Account ID that we know about. We can then move on to answering our second question. If we don’t know the AWS Account ID, and it’s not an AWS Service Account, then it’s stranger danger. I’ve come up with four different classifications for any AWS account relationship. AWS Service, organizational accounts, known accounts, or unknown accounts.