KKMIN

AWS IAM Roles & Video Game Classes

If you're a software engineer, chances are you've heard of Amazon Web Services (AWS) or have used AWS web services before. AWS is a cloud solutions platform akin to Infrastructure-As-A-Service where developers can "rent" services like databases, message queues or serverless functions, etc.

I started using AWS services recently for my own project, and I felt that there is a certain difficulty curve in learning AWS, not so much because of the services itself, but with things like configuration etc. In this post, I explore the parallels between AWS IAM (Identity Access Management) concepts which are essential in the configuration stage and more commonly understood concepts like video game classes.

Context

AWS does have documentation outlining what IAM is about, but it is very lengthy and can easily confuse new-timers who probably just wanted to use a simple service like DynamoDB or AWS Lambda. Instead they are confronted with all these identity concepts; I was personally one such person, and while I did read through the documentation lightly, the concepts only sank in after experimenting with the services a little bit more.

Users and Root

When you sign up for an AWS account, that account is automatically given root permissions. This means that this particular account has access to every single service available and has all possible permissions, and can also create other users (or sub-accounts if you will) under it via IAM.

This might seem strange from the perspective of an individual developer, but imagine that you are now not just an individual, but a representative of some entity like a company or an organization. The root account can be considered as the sysadmin account, and the user accounts are accounts of other people under the organization. Not all the users in your organization require permissions to access all AWS services, so AWS allows you to select what permissions to give these users via AWS IAM.

This is also a good practice to implement for our integrations with AWS services even if we are the sole user. We should restrict our integrations to use only the permissions they need (Principle of least privilege). That way, if our integration is compromised, the damage to our AWS account and resources are minimized by virtue of having restricted access to only the services it needs.

Policy

A policy is a document that dictates what set of permissions will be granted to the user that has it assigned. Each policy can contain permissions to access many different resources, and we can attach conditions to the policy as well. It is essentially the "contract" of what a user is allowed or not allowed to do. Here's an example of a policy, AmazonS3FullAccess, which will grant us access to the AWS S3 service:


{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"s3-object-lambda:*"
],
"Resource": "*"
}
]
}

The "Actions" array inside the contains "primitive" permissions that are available in AWS relating to its services.

Roles

AWS Roles can be thought of as a pre-defined user with some policies attached, except that it is not specific to any user and the role can be assumed by a user, effectively granting them the permissions in the role's attached policies. An important thing to note is that Roles do not have any long term credentials attached to it, like a user might have with policies; credentials are only temporarily obtained and discarded for a role when someone assumes that role. (For those familiar with Linux, this is a similar to the SUID concept, where a user executing a file with SUID executes it as the user who owns the file.)

One way to think of roles are like video game "classes". In many role-playing games, players (users in AWS context) can choose different classes, where each class has its own unique abilities. For example, a "tank" (defensive) class has skills that boost defense. A "healer" (supportive) class has spells that restore health.

Likewise, AWS Roles are like classes; each role has one or more policies (group of skills) attached to it, and our users can "assume" a role (choose a class temporarily) to gain the permissions granted by its policies:

Video Game Class

Tank

Defensive skills

Healer

Healing spells

Picture credits: AWS, FFXIV fan kit

AWS IAM is quite flexible in this regard, so you can craft your own policies, or create a custom role in addition to "stock" policies they have to fine-tune the access management to your needs. For example, you can create a new role that has access to both AmazonDynamoDBFullAccess and AmazonS3FullAccess; this could be analogous to a "Paladin" class that has both defensive and healing spells, etc.

Trust Policy and Assume Role

Earlier, we mentioned that roles can be assumed by users but that is not the full story as it is not a safe outlook; if any role can be assumed by any user, if one user that can assume roles get compromised, malicious actors may attempt to assume other unrelated roles which widens the attack vector.

To solve this, AWS requires us to establish a "bi-directional" trust relationship between a resource (role) and a user:

  • User must be given the "sts:AssumeRole" permission with explicitly specified roles (resources) they are allowed to assume
  • The resource (role) must specify a trust policy that specifies which principal (user) is allowed to assume role into it

Assuming a role will succeed only if these two conditions are satisfied.

Closing Thoughts

There's many more concepts to discover, such as setting up access using identity providers that supprot OpenID Connect, which might be useful if you want to integrate AWS services with another platform you are using such as Github. For now, the concepts highlighted in this post should be enough to get a simple integration with AWS services up and running.

← Back to home

Comments