Matt Morgan
Posted on June 12, 2023
I had the privilege and pleasure of speaking in the developer lounge at DC Summit this year. I chose a topic that I've frequently perceived as a stumbling block in a developer's journey to serverless and cloud: Identity and Access Management or IAM.
The gist of my talk is that I introduce some of the basic concepts which are critical to understanding IAM and then show a few practical ways to get hands-on experience. In particular I draw the distinction between IAM Users and Roles. I also had a section on IAM Identity Center, touched on OIDC and finished up talking about how frameworks can help us understand and find success using service roles.
After my talk, I had some questions from a listener and it quickly dawned on me that I had failed to explain that Identity Center Users are not the same as IAM Users. By omitting this critical fact, I'd not cleared up things as much as I'd hoped I could.
So let's try this again. Before I get to how overloaded "user" is, it's a good idea to define a few core concepts in IAM.
IAM Policies
Policies define the permissions that are being granted or denied. While they do nothing by themselves, they can be attached to all types of Principals (see below). Policies define the action or actions will either be allowed or denied and the resources which are governed by the Policy. If two Policies are in conflict (one says Allow and one Deny), then access is denied.
Here's a sample Policy from my talk:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sqs:SendMessage*"
],
"Effect": "Allow",
"Resource": "arn:aws:sqs:us-east-1:123456789012:my-queue"
}
]
}
This Policy allows the Principal to which it is attached to send messages to the referenced queue.
IAM Principals
An IAM Principal can refer to a human user or a workload that requires credentialed access to AWS resources. There are two main types of Principals in AWS in addition to root users. The primary difference between types of Principals is whether the credentials they provide are permanent or temporary.
Root Users
Root users are a special type of IAM User that carry additional permissions such as the ability to close the account. Each account has exactly one root user. The best practice is to use that root user to set up other ways to access the account, then stop using it.
IAM Users
We've already established that we aren't only talking about human users but it bears repeating that an IAM User is not necessarily a human user. IAM Users are frequently assigned to machine workflows. For example, a Jenkins server may have an IAM User which allows it to make aws cli requests in order to deploy applications. Or a web application may have an IAM User which allows it to store objects in S3. Humans may be assigned IAM Users which allow them to access the AWS console and/or execute cli or sdk requests to AWS services.
The important thing to keep in mind is that an IAM User is a long-lived or permanent credential. It lasts until revoked. IAM Users can provide one or more access keys, often in the format of AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. This is effectively a username and password combo for whatever resources can be managed by the IAM User's attached Policies.
IAM Users are still in common use, but they are no longer a best practice. The problem with IAM Users is access keys get passed around, checked into GitHub and exposed as environment variables. Since they don't expire, the risk of exposure is ever-present. It's not possible to work with IAM Users without facing this risk.
Not convinced? I was a bit of a hard sell, myself. I operated my personal account on the root user for more than a decade, then switched to an IAM User. Recently I locked down my root user, deleted my IAM User and switched entirely to roles. Why? In addition to wanting to learn how to secure my account properly, I also came to understand that using Roles is simply a better developer experience. I'll go into detail on my account setup in a future post.
Roles
Roles are used to grant temporary credentials to both human and machine users. This sounds like it might be complicated or annoying, but actually Roles are a lot easier to work with than Users.
Human users using Roles can leverage IAM Identity Center (formerly AWS SSO) which offers a pretty good experience, whether we're federating from Active Directory (a popular choice for enterprises) or managing users within Identity Center (fine for individuals or small team). We get an easy console sign-in experience and similarly frictionless command line access.
Roles are the simplest way to integrate services in IAM. We can grant a Lambda Function the ability to send messages to SQS. We won't need to provide an access key at runtime. The AWS SDK will automatically handle fetching credentials and refreshing them when they expire. The credentials will be scoped to the Policy that is attached to the Role we have given our Lambda Function. This may be complex to understand, but it's easy enough to operate and can largely be handled by a framework.
When it comes to outside access, whether an on-prem server or a third party CI/CD or monitoring service, we still have the option of using Roles by means of IAM Roles Anywhere and OpenID Connect (OIDC). These very similar capabilities allow us to establish a trust relationship between the 3rd party and AWS such that the 3rd party can assume a Role.
IAM User vs Identity Center User
IAM Identity Center is not a Principal like IAM Users and Roles. Instead it's a way to connect a human user to a Role, which can then be used to access the AWS console or services via the cli or sdk. The users that are managed in IAM Identity Center are not IAM Users. This is the point that I'd failed to convey to my listener.
Identity Center provides support for inviting users (again not IAM Users) or federating from an Active Directory or SAML provider. Users can be given permission sets or added to groups that have permission sets. Best of all, Identity Center works at the AWS Organization level, so everything is in one place, even if your Organization spans many AWS accounts and regions.
Comparing Users and Roles
I'm making the claim that we should use Roles, not only because they are more secure, but also because they provide a better developer experience. Let's walk through a few scenarios to see if that holds up.
Console Access
Human access to the AWS console is a basic use case that must be supported.
With an IAM User
Logging into the AWS console with an IAM User requires you to enter your Account ID, IAM user name, and Password, then (hopefully) enter a two-factor authentication code.
- Account ID required to sign in
- Multi-account not supported
- Federation not supported
IAM Users don't support federation so you can't use Active Directory or a SAML provider to sign in. If a human with access to an IAM User leaves an organization, the organization must take care to delete or disable the IAM User since removal from corporate directories will not automatically disable console access. This may lead organizations to limit console access when it's something that can benefit any developer who is developing in the cloud.
IAM Users don't scale well to multi-account scenarios. You have the option of creating separate users in each account or you can allow IAM Users to assume Roles in other accounts, at which point you're much better off using IAM Identity Center.
With IAM Identity Center (and Roles)
- Landing page with custom URL
- Multi-account, multi-role support
- Federation supported
IAM Identity Center allows for a much better sign-in experience and supports multi-account out of the box. It also supports federation so you can give an organization-wide single sign-on experience.
When signing in with IAM Identity Center, users can start at a custom, company-branded URL, choose the account they wish to access and choose the appropriate role for the task at hand.
Role and user management are handled in one place, even in multi-account scenarios. Administrators can create groups and permission sets to manage access. There are a couple of rough edges to Identity Center. For example, when viewing a user in the console, you can tell what groups they are a part of, but you can't easily tell if any additional permission sets have been assigned. That's only visible at the account level. This limitation in mind, it's still a far better experience than trying to manage IAM Users across multiple accounts.
Command-Line Access
Developers frequently require command-line access to AWS resources using tools like the AWS CLI, AWS CDK, or AWS SAM. This can be done with IAM Users or Roles.
With an IAM User
- Long-lived access key
- Separate access key needed for each account/role
- Credentials stored on developer workstation
- Credentials not tied to an identity source (no federation)
To use an IAM User at the command line, we must generate an access key and then place it in a credentials file which is normally inside a hidden directory on the user's filesystem. Although developers are recommended to store these credentials well outside a project path, they are occasionally committed to GitHub with disastrous results.
Developers also have the option of setting an access key and secret as environment variables, but this has the drawback of it being more burdensome to switch accounts and roles.
With IAM Identity Center (and Roles)
- Short-lived credentials
- Easy to set up multi-account, multi-role
- Developer need not handle credentials
- Credentials can be tied to a federated identity source
IAM Identity Center provides command line capabilities. While the short-lived credentials may be cached on a developer machine for speed, they don't need to be handled by any human so they are less likely to be mishandled, shared, or committed to a repository.
The experience of using IAM Identity Center is seamless and not disruptive while being one of the most secure ways to access AWS. I'll detail how I do this in a future post.
Third Party Machine Access
This could be an on-prem application, a SaaS partner, or even an application running in AWS that isn't using Roles.
With an IAM User
- Long-lived access key which must be handled by humans and stored somewhere
- Credential can potentially be exfiltrated from a compromised partner or runtime
- Traceability is poor - it can be unclear which applications or partners are using which access keys
This scenario is very similar to the developer cli access. We will have an access key and it must be stored somewhere. Usually the key is stored either in a credentials file on disk or as an environment variable. Either way, there's a risk of exposure of this long-lived credential.
The access key will need to be handled by humans at some point which is how they wind up on sticky notes, laptops, and other places they shouldn't be. Rotating access keys regularly helps with this problem, but that often involves manual work.
With Roles
- No copy-pasting of access keys
- Short-term credentials
- No credential need to be stored on the third party
To use Roles with a third party, we'll need to either use OpenID Connect or IAM Roles Anywhere. These options will again allow us to use short-term credentials. Most significantly, we can use 3rd party or on-prem applications without storing any access keys or other secrets. Instead we'll establish a trust relationship using certificates or ssh keys, similar to how developers around the world push code to their version control.
Service Access
Developers working in serverless and managed services will frequently need to create roles to allow intra-service communication.
With an IAM User
- Long-lived access key which must be handled by humans and stored somewhere
- Credential can potentially be exfiltrated from a compromised partner or runtime
- Traceability is poor - it can be unclear which applications or partners are using which access keys
It's not that common to see developers trying to put access keys into Lambda function. Many kinds of integrations, such as an SQS queue subscribing to an SNS topic, have no IAM User option at all. Any compute layer such as Lambda, Fargate, or EC2 can use IAM Users but all of these can support roles.
In addition to security concerns, access keys must be stored somewhere to be provided to an application. Often they are injected during a CI/CD pipeline. This wouldn't be necessary using Roles.
With a Role
- Short-lived credentials with refreshes handled by the SDK
- No copy-pasting access keys
- Framework support
- It's your only option in many scenarios!
As previously stated, Roles are the most common way to manage these interactions and are the only option in many cases. Developers who are using frameworks like the AWS Cloud Development Kit or the AWS Serverless Application Model can take advantage of framework features that make Role management relatively easy. The Roles and Policies can be created and assigned using these frameworks. Here are a couple of examples of how that works:
AWS CDK
const queue = new Queue(this, 'MyQueue');
const function = new Function(this, 'MyFunction', {
// more args
});
queue.grantSendMessages(function);
This code will create a function role and assign it a policy that allows it to send messages to the queue that was created.
AWS SAM
Resources:
MyQueue:
Type: AWS::SQS::Queue
MyFunction:
Type: AWS::Serverless::Function
Properties:
# additional properties
Policies:
- AWSLambdaBasicExecutionRole
- SQSSendMessagePolicy:
QueueName: !GetAtt MyQueue.QueueName
This is functionally equivalent to the CDK code.
Not using Lambda? Both EC2 and Fargate also support Roles.
Conclusion
In this post, I've defined IAM Policies, Principals, Users, and Roles. I've described IAM Identity Center and tried to explain how the users in Identity Center are not IAM Users.
Beyond that, I made the case that switching from IAM Users to Roles delivers a superior developer experience in addition to being more secure.
The best security tools are the ones that make the right thing the easiest thing. IAM Roles and Identity Center succeed in delivering not just a safer experience, but also a better developer experience.
I hope this post has helped to clear up some of the core concepts in IAM. I invite readers to add questions in the comments if any of these concepts remain unclear.
Posted on June 12, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.