There’s no drama like niche AWS nerd drama. This post will definitely undoubtedly indisputably put an end to some of the longest running such drama. Are AWS account IDs secrets?
Corey Quinn already put this issue to bed in 2022 when he got confirmation from AWS’s Director of Worldwide Analyst Relations & Market Insight Steven Armstrong: “Account IDs are not considered sensitive.” We’re ripping it from its peaceful slumber like a five year old does to their parents on Christmas morning. If you aren’t a parent, enjoy your sleep you lucky person you.
The annoying thing about this debate is that everyone is right. Corey is right. AWS documentation is right.
Eric Brandwine, AWS VP and Distinguished Engineer is right.
Stack Exchange user nikobelia is even more right.
However, they are also degrees of wrong in that they are missing or under representing the realities of cloud misconfigurations and AWS hacking practicalities.
In the cloud, there's a shadow, not everything's right,
Misconfigurations hidden, away from the light,
AWS hacking, a practical plight,
Realities missing, we gotta bring to sight.
That’s a rap I wrote for you to make this post more credible.
Let’s explore.
Almost every attack requires an identifier
With some exceptions, if you want to hack something in AWS you need a target of some sort, typically a resource, an identity, or account – something you can use or access.
- Want to assume a role in somebody else’s account? You need the specify the target role ARN.
- Want to read confidential data from a DynamoDB table? You need to use an identity in the target account and specify the table name.
- Want to publish a malicious message to a notification topic you don’t own? You need to provide the topic ARN.
- Want to read from queue in another account? You need to specify the queue URL, which is made up of its account ID, region, and queue name.
- Want to retrieve someone’s vault archive? You need to supply the target account ID and vault name.
A quick click around hackingthe.cloud reveals some similar requirements for exploitation and privilege escalation techniques.
- Abusing ECR for lateral movement requires the account ID of the target container registry
- API Call Hijacking via ACM-PCA requires the ARN of a certificate authority to target
The need to know a target account ID or ARN (which is itself composed of an account ID amongst other information) creates an unintended security control. If an attacker can’t identify a target account ID, they can’t hack it. With ~1,000,000,000,000 possible 12 digit combinations, an account ID has some similarities to a web session ID.
Going from account ID to ARN is sometimes easier than you expect
In 2016 a highly sophisticated threat actor that goes by the moniker “dagrz” discovered it was possible to validate whether an IAM principal exists or not, cross-account, without touching the target account. It continues to work to this day.
When creating or applying an IAM policy, the AWS policy engine checks the validity of an “Principal” elements and throws an error if it does not exist. An attacker or curious researcher can use this quirk to check for common role names and users within an account.
Using the validate principals tool from aws_pwn (or similar tools such as Quiet Riot), we can see that the account ID Corey Quinn published in his blog post exists and it contains the workspaces_DefaultRole role.
% ./validate_iam_principals.py \
-i ./quiet-riot/wordlists/service-linked-roles.txt \
-a 024196225137 \
-o out.txt
{
"principalName": "root",
"accountId": "024196225137",
"arn": "arn:aws:iam::024196225137:root",
"exists": true,
"error": null
}
...
{
"principalName": "role/workspaces_DefaultRole",
"accountId": "024196225137",
"arn": "arn:aws:iam::024196225137:role/workspaces_DefaultRole",
"exists": true,
"error": null
}
There aren’t as many neat tricks for enumerating resources, especially without touching the target. AWS has done a relatively good job controlling these information leaks. These days most services respond with a generic “resource does not exist” style error
Previously discovered disclosure techniques include:
- S3 buckets – Accessing S3 URIs produced one of three responses:
- A file list
- An “access denied” error
- A “bucket does not exist” error
- SQS queues – Accessing SQS ReceiveMessage URIs produced one of three responses:
- The message ID
- An “access denied” error
- A “Queue doesnt exist or you dont have access” error
Regardless, If a resource exists, and it is overly permissioned, accessing it is likely a matter of calling the read or write API with the correct identifier.
Everyone exposes resources, very few are found
The Distinguished Cloud Historian Scott Piper maintains a list of AWS eXposable resources. There are a lot. Adjacent is a sort of law of AWS derived from Frichette’s Law – any AWS resource that can be exposed, will be exposed by someone (usually many many someones).
Let’s say you wanted to verify this claim, how could you do it? It just so happens your boy works at a company that operates a cloud security SaaS platform. We help customers identify and solve AWS security issues every day. We also have access to aggregate data about common risks and attacks they are facing.
I can tell you folks indeed expose resources unintentionally, all the time. Our data shows just under 55% of AWS accounts have a publicly exposed resource that is not exempted (exemptions are our way of flagging that it’s intentional). It’s just part of cloud lyfe.
Which begs the question, if so many resources are exposed why aren’t more companies getting their AWS resources hacked??????????????
I have an answer for you, but you might not like it. Those exposed resources are just never found by bad actors. It’s because AWS identifiers, and especially account IDs, are not well known. They are leaked and often discoverable (that’s another blog post) but they aren’t currently well known.
It’s bed time for that 5yo kid
I’m not sure how this became a parenting blog post but I guess we have to live with the decisions we make. Let’s definitely undoubtedly indisputably put this issue to bed. For practical reasons, AWS account IDs should be treated as confidential.
It’s true that:
- Account IDs have to be shared and used internally, and sometimes externally
- Plaintext account IDs are required to build anything in AWS
- Knowing an account ID on its own is not enough to hack anything
- The AWS threat model assumes your account IDs are known
But it’s also true that:
- If you leak you’re account ID, an attack can identify more about your account , like the third party service you use (through principal enumeration)
- You will likely expose as resource unintentionally at some point
- You’re probably relying on the fact that no one knows your account ID as a security control right now but aren’t aware of it
So my advice, our advice, the thing we do, is to limit the exposure of your important AWS accounts as much as possible. It’s not feasible to encrypt them and limit distribution within your organisation like a traditional secret, but there are lots of practical steps you can take to limit likelihood and impact of exposure:
- Use parameters such as environment variables to pass account IDs and ARNs. Avoid hardcoding account IDs in code and configuration.
- Publish resources like Images, lambda layers, applications, and integrations from separate purpose-built AWS accounts as source account IDs are also published as part of the process. Avoid doing so from production accounts.
- When building integrations that need to be described in documentation, use separate purpose-built AWS accounts because documentation is often essentially public.
- Make principal names and resource names unpredictable. This doesn’t mean they must be random or descriptive but at minimum avoid defaults.