Do you work with infrastructure code and find yourself asking, “what would happen if we made this change?” Deriving meaning from looking at code alone is challenging – let’s visualize it!
A common way to frame IAM is with the statement, who can do what under which conditions. As such, it’s natural to think of AWS IAM as working forward – Principals performing Actions against Resources. This isn’t always the case in practice – sometimes you have to work backward from a Resource to answer the question, who can access this? Phrasing is only a frame of reference, what’s important when deriving permission sets is parsing all applicable policies, which can include:
- Inline Role policies
- Inline User policies
- Resource policies
- Permission boundaries
- And more…
To demonstrate a common permissions scenario, let’s introduce A Team Called Quest (ATCQ) – where the cloud is their native tongue. Even when their environment was small, it was a non-trivial problem that consumed significant resources and time. As the company grew, so did its policy sprawl, making it increasingly difficult to wrangle. Exercises in exploration quickly turned into mysteries… and not the fun kind.
Let’s check-in with the team at ATCQ to ask “what if?”
What's The Scenario?
Our previous Database Engineer at ATCQ, Manuel, only used local database authentication for RDS access. Our new engineer João is intent on modernizing access controls and wants to implement stronger IAM authentication for RDS. He asked our Operations team what he thought was a simple question – “Which IAM Groups or Services have access to this RDS instance? More specifically, who can connect to it using the IAM action ‘rds-db:connect’?”
The environment is fully managed via Infrastructure as Code, so the Operations team can inspect the Terraform to answer the question.
Here’s the codebase for inspection.
How can we tell who has access to this RDS instance?
The Old Way
AWS doesn’t provide a simple way to look at all access vectors from the perspective of a single resource, so we would have to enumerate through all of the applicable policies – this takes a lot of time!
We could grab all of the policies in a single AWS account with the following command, but even for a simple account, it’s far too much information to parse through.
% aws iam get-account-authorization-details | wc -l 42917
We could grep this output for RDS, but what exactly would we grep for? “rds:”? What about *:* permissions? Because of how IAM uses wildcard expansion it’s hard to decompose an exact matching for this permissions set.
The New Way - Visualizing IAM
Using a visualization technique that gives us a complete view of an account, we can work backward from RDS, finding out the Principals who can perform which Actions because of what Policies.
Here’s a view of the account filtered by the RDS service. Of our 3 regional teams, APAC and LATAM have full RDS access through two different policies.
However, João’s question is even more specific - what principals in the environment can execute a specific action, ‘rds-db:connect’. Let’s filter the view to show only that Action.
In a few steps, João can quickly identify which AWS IAM Role can access the database and which IAM Users can assume it, something that could take hours with native tooling.
As you’ve seen, any of the legacy methods for discovering which principals have the ability to execute an action on a resource is a difficult problem due to the way AWS IAM is designed. Even with Terraform code, it still requires us to find every single principal, find all the IAM policies attached to them, and parse them.
Our method of visualizing an entire AWS environment is much easier - we can pivot the access vectors based on a single resource to see who has access. We can even filter for a particular IAM Action and see which principals can access it, regardless of how IAM constructs the allowed path.