Identity and Access Management (IAM) is at the forefront of how users experience an application and must be properly managed in order to have adequate security of an enterprise. AWS considers IAM to be so foundational to building a secure cloud environment that it is included as the first major content section of the AWS Well-Architected Framework Security Pillar.
With cloud adoption rapidly scaling, many organizations are struggling to control identity sprawl in which there are many unmonitored admin roles, and confusing access restrictions which make their applications not only difficult to use, but ultimately unsecure as well. However, with the proper use of AWS’s suite of identity services roles can be aggregated, admin roles can be minimized, high-privilege roles can be monitored, and infrastructure access can be clearly defined for each user.
This foundation covers a suite of strategies and modules for maintaining IAM permissions at the account and resource level. Therefore, this foundation is particularly relevant for application owners since they are typically provided with an AWS Account for their team and are largely responsible for managing the IAM strategy for the account.
Prescriptive Guidance
Before diving into account-level best practices, it is important to acknowledge that there are approximately six layers of policy logic that exist ranging from Service Control Policies (SCP’s) at the organization level, all the way down to resource-based policies at the resource level. Although we will be focusing on account-level permissions mechanisms in this section, it is important to acknowledge the broader picture of how the policies interact at different levels of the cloud environment. Any time that an action is performed in AWS, a multi-stage permissions evaluation process is followed. The illustration below depicts the permissions evaluation process of the main layers of AWS policy evaluation logic.
Definitions
- Root User — The root user is the IAM entity that is used immediately after account creation, the effective username of the root user is the email associated with the account’s creation. Preventing access to the root user is integral to the security of the account because the root user’s permissions cannot be restricted.
- IAM Policy — IAM Policies are one resource that IAM Users and Roles view to evaluate whether or not they have access to perform actions within AWS.
- IAM Principal – All actions done within AWS are done by IAM Principals, which are either IAM Users or Roles.
- IAM User — IAM Users consists of a name and credentials which interacts with AWS resources. These should be tied to existing identity providers such as Active Directory, using standalone IAM Users is discouraged.
- IAM Group — IAM Groups are collections of IAM Users, which should be used frequently instead of hardcoding specific permissions for a singular user.
- IAM Role — IAM Roles have a specific set of policies attached and can be assumed by multiple entities in order to gain access to a subset of AWS resources.
- AWS Resource – An AWS Resource can be any AWS entity that can be worked with, such as an EC2 instance, an S3 bucket, or an RDS database.
- Resource-Based Policies — Policies should be written to be focused around individual resources / resource groups rather than exclusively actions in order to have more granular controls.
Best Practices
Root User Management
The root user should only be used in true emergency situations after the account is created. In fact, we recommend the credentials must be stored in a Privileged Access Management (PAM) tool with access limited to a select group of top level account admins that can access the credentials. One option that is recommended is a PAM solution, but any other password/secrets manager system that is already used within the organization can be sufficient with proper access controls.
Multi-Factor Authentication (MFA)
In order to create and enforce a secure cloud environment, MFA must be utilized. News regarding a major password leak seems to happen every month, and the inclusion of MFA in an organization allows many of those passwords to be effectively useless to the attacker without MFA. The enablement of MFA is a necessary component of a secure infrastructure.
To ensure that every IAM Principal in the account is properly secured, we highly recommend that every IAM Principal has MFA enabled and configured, with the sole exception being service roles and service accounts.
Resource-Based Policies
Resource policies such as S3 Bucket Policies and KMS Key Policies should always be used in conjunction with other permissions policies in order to specifically allow distinct IAM principals access to perform actions on the resource in precisely defined manners. These policies are written with the list of actions allowed, and then what IAM principals are allowed to take such actions.
Identity-Based and Resource-Based policies do have a functional overlap, but the distinction lays in the level of fine-grained control desired. For example, a snippet of an example S3 bucket can be seen below:
"Statement": [
{
"Sid": "IPRangeAllow",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::EXAMPLE-BUCKET",
"arn:aws:s3:::EXAMPLE-BUCKET/*"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "54.240.143.0/24"
}
}
}
]
In this example, an additional identity policy is used to determine which principals can perform which actions on this bucket, and then, in addition to that policy, the actions are further restricted by the above bucket policy to only allow actions that originate from the range of IP addresses specified in the condition.
Permission Boundaries
Unless there is an explicit allow in the Identity-Based policy, permissions boundaries are the next line of defense. These policies are similar to a policy attached to a role, however, they go a step further and prevent the user from creating a role or escalating their privilege to go further than what is outlined in the permissions boundary.
The inclusion of permissions boundaries is a core step in creating effective permissions. It is crucial that any role that has the ability to create other roles should have a permissions boundary on top of it to prevent users from simply creating an admin-level role and assuming that to get around any permissions blocks.
Session Policies
We recommend leveraging Session Policies in situations where role sprawl is becoming an issue and carefully designed Identity-Based Policies cannot address it. This can be accomplished because when logging into the AWS console from a SAML provider, SAML configuration can be passed through the request to include certain PrincipalTags, which can then be used to write Session Policies.
For example, this policy below takes advantage of reading PrincipalTags from the principal attempting to take an action.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "True",
"Action": "ec2:*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalTag/PII-Access": "true"
}
}
}
]
}
In this example, the PrincipalTag, included with the SAML request of the principal’s sign in, must include the kv pair of “PII-Access”:”true” in order for the principal to have access to taking “ec2:*” actions on resources.
By utilizing Attribute-Based Access Control, in which tags are inspected in policies and permissions are given appropriately, role sprawl can be minimized, and one policy is able to be applied to allow appropriate levels of permissions as defined by the attributes of the resources themselves.
Identity-Based Policies
Identity-Based policies determine what effect (allow/deny) an IAM principal’s actions can have on specified resources. By creating and attaching multiple policies to IAM Users, Groups, and Roles, administrators are able to achieve a comprehensive permissions strategy that clearly states what actions users are able to take, in a modular manner that is easily adjustable to each individual role’s needs. While it is possible to leverage IAM Users and Groups to create Identity-Based Policy Strategies, we recommend primarily relying on IAM roles.
Roles should be designed around needs of a specific job-function, this allows for an employee to work within AWS within a consistent role and it allows team members to come and go from the team and all they need is access to the role in order to do their single job. If a team member wears multiple hats, they can have multiple job-function roles, but this should be minimized in order to provide that manageable and consistent user experience with minimal role-switching. By having roles confined to job functions, we are able to limit the blast radius in case a role is compromised. The blast radius is limited because roles are dynamically assumed and upon assumption the principal that assumes it is given a access key, secret access key, and session token that have a short time-to-live (TTL) and must be renewed.
The following are a few examples from our recommended list of IAM Roles that should be present in each account. We recommend deploying these to accounts via Control Tower Customizations, as discussed in the Account Foundation:
AccessAdministrator | Allows Full-Control of IAM, along with Read-Only access to AWS Organizations |
AccessAuditor | Allows Read-Only access to IAM and AWS Organizations |
BillingAdministrator | Allows Full-Control for Billing, Usage, & Payment items for AWS Portal and AWS Billing Console |
BillingAuditor | Allows Read-Only access for Billing, Usage, & Payment items for AWS Portal and AWS Billing Console |
Break-Glass | Allows Full-Control to nearly all Resources, only to be assumed in emergency scenarios |
Aside from roles that are assumed by humans, there are also automation roles. These roles behave the same, but are purely used by applications such as Terraform, Jenkins, or Splunk. This separation allows for logging systems to have a much clearer picture of who is performing what actions, and can detect problems in automation much more clearly.
IAM Role Broker
Even after following our guidance to carefully create a strategy to optimally leverage the different levels of permissions as outlined in the Best Practices discussed above, account administrators still have many manual responsibilities. The most significant of these is being responsible for creating and managing roles for new and existing developers.
Due to the constantly evolving needs of developers and the tedious process of creating least-privilege roles, many account administrators end up provisioning overly permissive roles and policies filled with wildcards (*). While the administrator thinks they are just providing the developer with the ability to deliver their solutions at a greater velocity, they are also inadvertently introducing serious vulnerabilities into their environment with each overly permissive role.
To address this problem of policies being either too restrictive, too permissive, or too difficult to effectively write manually, we have developed the Identity Broker module. The Identity Broker provides account administrators with a self-service module to quickly create least privilege permissions based on permission requirements of users. This module should be leveraged for lower environments to allow for more development velocity, but this is not meant to replace comprehensive security reviews of IAM policies before promotion to production environments.
Components
- Service Catalog — The frontend of the architecture is the Service Catalog product which vends the appropriately configured Lambda depending on the parameters specified by the user deploying the product.
- S3 — This storage bucket is exclusively used for storing the Lambda function’s code in a consistent, stable, and secure location.
- Lambda — The compute component behind this architecture is responsible for the calling of the Policy Sentry library to carefully define the properties of the IAM Policy and then compressing that list to work around the policy character limit.
- Policy Sentry — This Python library is used for the collection of the full list of permissions related to each service and the requested access level.
- IAM Policy – The IAM Role Broker’s primary functionality is the creation of the custom policy which limits a principal’s access to exclusively being within the confines determined.
- IAM Role – The IAM Role created by the IAM Role Broker has the IAM Policy attached and is configured to work with the account principal
How It Works
The IAM Role Broker is a custom module in AWS which involves Service Catalog vending a Lambda function, triggering said function, and the function creating a role and policy with the specifications requested by the service catalog product’s parameters.
The Service Catalog product attaches 3 pieces of information to the Lambda creation CloudFormation template:
- AccessLevel
- What access level of role are you provisioning? (‘Read’, ‘Write’, ‘List’, ‘Permisssions management’, or ‘Tagging’)
- ActionCategory
- What category of resources does your role need access to? (‘Kubernetes’, ‘Storage’, ‘Logging’, ‘IAM’)
- (More categories can be configured via the configuration JSON file)
- RoleorPolicy
- Would you like a role and a policy generated, or just a policy? (‘Role’, ‘Policy’)
- TeamName
- What team’s resources does your role need access to? (‘Security’, ‘QA’, ‘IAM’)
- (Any team name can be used, DevOps and IAM are simply examples)
The Lambda function, which is written in Python, goes through the ActionCategory’s list of services (for example, the Storage team needs access to S3 actions), then uses Policy Sentry to narrow down the list of permissions to be either read or write level of permissions and then creates the permissions set via CDK to only allow these actions, on these services, with resources with the appropriate team’s tags.
After the text of the policy is generated, the Lambda function utilizes boto3 to create the IAM Role and Policy resources.
An example policy made with the request of needing “Read” actions to the “DevOps” team’s “Storage” services can be seen below:
{
"Version": "2012-10-17",
"Statement": [
{
"Condition": {
"ForAllValues:StringEquals": {
"aws:ResourceTag/SupportTeam": "DevOps"
}
},
"Action": [
"s3:Describe*",
"s3:Get*",
],
"Resource": "*",
"Effect": "Allow"
}
]
}
By utilizing the IAM Role Broker, organizations can have a secure yet accessible cloud platform that truly implements the principle of least privilege in an incredibly precise manner.
High-Privilege Role Alerting
Another common shortcoming of the IAM approach at many organizations is the lack of monitoring and oversight of high-privilege IAM roles. Since every account has high-privilege roles (i.e. admin and break-glass roles) that should be very sparingly and have a very restricted set of users that can assume them, it is important to know when they are being accessed. This is because if any of these roles are compromised and assumed by threat actors, significant damage can be inflicted on the account including taking systems offline, deleting backups, and creating backdoors to access the account in the future.
To mitigate the risk associated with highly privileged roles, any time they are assumed an alert should be sent out to appropriate security teams and stakeholders so appropriate actions can be taken. Our High-Privilege Role Alerting module provides a self-service approach to provide alerting for highly privileged roles by simply providing the role name and the email address that should be alerted.
It is worth noting that for the purpose of this example, we only implement role alerting, but this exact pattern can be used for any type of IAM Principal.
Components
- Service Catalog — The frontend of the architecture is the Service Catalog product which vends the appropriately configured event, Lambda, and SNS topic depending on the parameters specified by the user deploying the product.
- S3 — This storage bucket is exclusively used for storing the Lambda function’s code in a consistent, stable, and secure location.
- EventBridge — The EventBridge Event is the mechanism that does the actual detection of the role assumption in the account which triggers the Lambda.
- Lambda — When triggered, the Lambda generates a message detailing the event that triggered it and when it occurred, and then sends the constructed to SNS
- SNS — The SNS topic is the AWS mechanism for sending messages from AWS to a user specified endpoint, which in this architecture is an email specified by the Service Catalog parameter.
- Break-Glass Role — A role designed to have a very high level of permissions which should only be used in an emergency scenario. This role should be very carefully given, and it should alert when assumed so that there is never a situation where this role is used out of convenience. This role should be checked out via a solution such as a PAM in which approval must be first given before given temporary access to the role.
How It Works
From an implementation perspective, EventBridge Events can be used to trigger a Lambda function that sends a message to SNS, which can alert via email- as seen in the diagram below.
The Service Catalog product prompts the user for the role they’d like to monitor for assumptions and also the email they’d like alerts to be sent to, and then the event, lambda, and topic are created. Following this creation, the subscription must be confirmed and then the module is fully deployed and ready to monitor that role for assumptions.
As an alternative configuration, messages can be sent to Slack directly from the Lambda function via an API call, or SNS can be configured to send a message to a phone number. Regardless of the last step and method of alerting, monitoring should be enabled on the Lambda function to ensure an admin can go back and find when a user logged into the account and from where.
Blueprint
HighPrivilegeRoleAlerting Blueprint contains the CDK code needed to deploy a Service Catalog Product which vends a Lambda Function, an EventBus Event, and SNS Topic used for notifying individuals in an organization when an IAM role is assumed.
IAMRoleBroker Blueprint contains the CDK code needed to deploy a service catalog product which vends a Lambda Function, which itself vends an IAM Role and Policy with the permission set specified in the Service Catalog’s parameters
Benefits
- By avoiding using the root user for day-to-day activities and only using it for the highest of emergency scenarios, mistakes by the unrestricted root user can be avoided, the logging and monitoring of actions can be improved, and the overall security of the account is heightened.
- The utilization of MFA leads to a more secure login experience that would help prevent bad actors from breaking into the AWS environment- even if they had the username and password of an IAM user.
- By following the our recommendations of how to use the different layers of permissions policy types (resource policies, identity policies, etc), a full and comprehensive permissions structure will exist that allows for the incredibly granular and precise control around what users can take what actions.
- The IAM Role Broker makes role generation and proper policy creation easier which allows for a better user experience and a more secure cloud environment.
- Privileged role assumption alerting allows the organization to be proactive when it comes to understanding a potential security incident. It also prevents admin-level roles from being assumed unnecessarily because users can’t simply assume a High-Privilege role whenever their permissions are blocked without alerting their team.
End Results
While there are many different components involved with securing the cloud, a carefully architected IAM strategy is paramount. A solid IAM strategy allows engineers to develop quickly, provides key stakeholders with a comprehensive picture of the actions that can be performed by different IAM principals, and results in a more secure cloud environment overall. Security without reasonable user experience can lead to workarounds and dysfunction, and by implementing this solution, both key stakeholders and engineers can all be satisfied with the result.