AWS IAM: A Comprehensive Guide Toward Least Privilege

This article discusses (to a decent depth) the AWS mechanisms we can use to achieve more robust permissions on AWS. It also serves as a primer for how AWS IAM works (skipping the basics) and a compendium of helpful (and good) resources.

You are probably already familiar with the principle of least privilege (PoLP) (it even has a Wiki page). The gist is that an identity should have the permissions required to perform its function and nothing more. And there are good reasons to strive for this:

  • Limit the blast radius in case of credential theft/leak - i.e., what an attacker might be able to do if they obtain credentials to your environments. Sure, you might not access your AWS account(s) from an internet cafe, but accidents can still happen (check out Rhino Security Labs’ article for some scenarios) (this is also what happened with the recent Snowflake breach).
  • Avoid/minimize accidental data deletion. One second, you investigate an issue in production, find it, take a break, return to what you’ve been doing before the production issue, and forget you are still in that environment (happened to GitLab, too).
  • Avoid/minimize (ill) intended data deletion. Sometimes, managers have to make difficult decisions; sometimes, people don’t accept those decisions easily (like this one).

If you only use AWS Lambda, DynamoDB, and S3, most of your team could do their job with access only to those services. Sure, they will probably also need access to CloudWatch (logs from Lambda), SQS/SNS/API Gateway, CloudFormation, some IAM (those functions need roles and policies to execute; also, your colleagues might want to change their password), ECR (running Lambda with containers is a good option, especially for large functions). You also probably want a decent experience for your colleagues who are still using the AWS console occasionally (so more permissions, or they will see a bunch of “not authorized” error messages throughout the console). The list of three services quickly spiraled into “I’ll just give everyone AdministratorAccess and rely on them to behave responsibly” (we understand).

Starting with broader permissions and gradually moving towards least privilege is a practical approach. It’s important to remember that achieving least privilege is a journey, not a destination. If you have multiple AWS accounts (preferably using AWS Organizations), you could grant your team broader permissions in non-production accounts and read-only permissions for the production account(s). Be careful which policy you use here: ReadOnlyAccess grants read access to everything, including IAM and data stored in S3 and DynamoDB, and even the code used by Lambda functions - consider using ViewOnlyAccess or SecurityAudit, which provide access only to metadata.

Being Pragmatic

Speaking of multiple AWS accounts, least privilege is one aspect of security. Others include:

  • Separating workloads/environments into different AWS accounts
  • Using short-lived credentials (i.e., use roles) (as opposed to IAM users with access keys). With this, even if someone manages to steal credentials, they will be good for a few hours.
  • MFA
  • Granting permissions through groups
  • Logging and auditing (CloudTrail)
  • Use infrastructure as code, automatic deployments, and GitOps
  • Backups and a decent (and tested) disaster recovery (DR) strategy

If you are at the beginning of your security journey, focusing on the above will provide a higher return on investment than trying to optimize permissions. In AWS, you can achieve the first three by using AWS Organizations (AWS provides some ideas for organizing your accounts - the entire whitepaper is worth reading) and AWS IAM Identity Center (here is a good starting point). Bonus points if you manage your organization and IAM Identity Center through infrastructure as code (Terraform works great for us).

Service Control Policies

There is another benefit to using AWS Organizations: Service Control Policies (SCPs). They are similar to IAM policies, the main differences being that you apply them at the account or organization unit (OU) level and that you don’t grant permissions using them (i.e., it is not enough that an SCP allows users to create EC2 instances - they will also need an IAM policy), but you can deny specific operations. These are the operations you know for sure should not take place (a.k.a. invariants), such as:

  • Limiting actions to specific regions: You might be legally obliged to keep your data in Europe (eu-central-1, eu-west-1, etc.), India (ap-south-1, ap-south-2), or Singapore (ap-southeast-1). Here is an SCP for this.
  • Disallow changing certain services: One of the first things an attacker will do is attempt to turn off auditing, logging, and any security service. Moreover, from a compliance point of view, proving proper configuration management is key. For example, you can prevent everyone from disabling AWS CloudTrail (notice that controls in the Control Tower are SCPs).
  • Block access for the root user: Using the root user is rarely a good idea. You can use SCPs to deny all actions for the root user, with one caveat (and the reason I chose to add this point): it will not block the root user in the management (or root) account. In fact, SCPs do not apply to the management account, which is one of the main reasons you should not run your workloads there.

There are more good use cases for SCPs, such as limiting the EC2 instance types (you want to keep the costs for sandbox accounts under control), requiring certain tags, or preventing adding internet access to existing VPCs. You can read more about SCPs in the AWS docs, and you should check the limits applicable to AWS Organizations (and SCPs) (e.g., you are limited to 5 SCPs per account/OU - here are some guidelines).

Zones of Trust

Now that you have workloads and resources segregated using AWS accounts (and organizations), you should keep track of what can be accessed from outside the zone of trust. While, by default, nothing outside of an AWS account can access resources from the account, resource-based policies can change this. Any resource that supports resource-based policies, such as S3 buckets, SQS queues, DynamoDB tables (recently), and IAM roles (the trust policy is a resource-based policy), is subject to external access. You can find all services supporting resource-based policies here.

Side note: The evaluation logic for resource-based policies works differently depending on the principal (the principal is also the main difference between IAM and resource-based policies. For IAM policies, the principal is implied based on the identity to which the policy is attached. For resource-based policies, the principal must be specified). If the principal is from the same AWS account, the evaluation logic looks at the union between the IAM policy attached to the principal and the resource-based policy (i.e., it is enough that any of those grants access). For cross-account, both the IAM and the resource-based policy must grant access.

There are two ways an external principal can access a resource from your account:

  1. If the resource-based policy allows them to.
  2. Through a role they can assume and that grants them access to the resource.

Notice that both the bucket and the role's trust policies can allow any principal (even unauthenticated ones).

Now that we have identified the main IAM mechanisms through which external access can be granted, we need a way to manage them. While SCPs can help you set guardrails within your AWS organization, they do not apply to principals from different AWS organizations. (However, you can still benefit from AWS Organizations in other forms, such as organization-related condition keys such as aws:PrincipalOrgId and aws:PrincipalOrgPaths. For example, you can write an S3 bucket policy to allow only principals from your organization. You can read more here.)

The recommended way to keep track of resources that can be accessed from outside of your account/organization is IAM Access Analyzer.

IAM Access Analyzer External Access

One of the features offered by IAM Access Analyzer is the possibility of identifying resources accessible from outside your zone of trust (which can be either your AWS account or your AWS organization when creating it from the org management or delegated admin account). It interprets the resource-based policies attached to your resources and tells you if they allow external access (supported services). It also interprets S3 bucket ACLs:

Here are a few important facts about IAM Access Analyzer external access:

  • Even though free, you must enable/create an analyzer for external access in each region where you have resources, even for S3 (buckets are regional resources). One exception is IAM roles: since they are global resources, all access analyzers will generate findings for them.
  • You can create multiple analyzers in the same region (still free for external access). For example, you could create one analyzer per org account or analyzers with different archiving rules (when specific external access is intended).
  • You can use it to preview external access while editing the resource policy.
  • It even understands condition keys like the ones mentioned above.
  • It does not look at any logs or CloudTrail, which is good. However, behind the scenes, it uses CloudTrail to detect changes to your policies so it knows to rescan them. It also does a full periodic scan every 24 hours.
  • It also reports roles used for IAM Identity Center and EKS IRSA. You can read here how to deal with such common exceptions.
  • While you should use the preview functionality when editing resource-based policies to prevent unintended external access, you can also set up notifications for findings generated by the analyzer based on EventBridge. Check out this AWS workshop. It is for IAM Access Analyzer unused access, which is covered below, but the idea is the same.

Managing Permissions for Identities

Going back to the idea of starting with a permissive AWS-managed policy when granting permissions to your colleagues, one important mention here is that there is a reason why these policies are called AWS-managed: they are continuously updated by AWS. If you use them, the permissions granted to your identities will likely grow over time (as AWS adds new services and features). If you want more control, you can create a customer-managed policy by copying its JSON body.

There are other policy types we can leverage besides resource-based policies, IAM policies, and SCPs. One important mention regarding the various types of policies is that you can only grant permissions through IAM and resource-based policies (and ACLs for S3, but this is beyond the scope of this article). All other policy types act as boundaries, which is why they tend to be simple (e.g., deny all actions for a specific service). The figure below illustrates the various types of policies:

If you want to understand better how these policies complement each other, we recommend this re:Invent talk.

Note: We will discuss permission boundaries in more detail below, but one interesting fact is that you can use SCPs to enforce roles to be created with permission boundaries.

Note: We can also leverage VPC endpoint policies. These are resource-based policies that control which principals can use a VPC endpoint (interface or gateway).

Workload Identities

Another important aspect is the distinction between human identities (i.e., the people from your organization who need access to the AWS environments—a.k.a. workforce) and non-human identities (NHI) (a.k.a. workload identities). Just like someone can steal credentials from people, they can steal credentials from an EC2 instance by gaining access to it or through Server-Side Request Forgery (SSRF) (read more here). From a permissions point of view, human identities are more dynamic (people come and go, change departments, projects, etc.), while NHIs require a more stable set of permissions and tend to use those permissions more frequently. Moreover, workloads don’t usually need permissions to create other identities and grant permissions. So, in most cases, achieving optimal permissions for workloads should be more attainable.

A useful best practice for refining workload permissions is to redeploy the applications/workloads on a schedule (e.g., once a month), even if nothing changes. This practice ensures that permissions exercised during application startup are accounted for (e.g., the app might read parameters from SSM Parameter Store or load some data from S3 during initialization). Furthermore, you could rebuild the application, which should address many vulnerabilities in the base image if you use containers.

Permission Boundaries

If SCPs can represent guardrails at the organization/account level, permission boundaries act at the user/role level. Our colleagues often need permission to create other IAM entities (e.g., IAM roles for Lambda and EC2 instances). However, an ill-intended actor might abuse this, resulting in privilege escalation - e.g., they create a role granting more permissions than their current identity and assume it. We can prevent this using permission boundaries.

While you can attach a permission boundary (which is an IAM policy) directly to the IAM roles/users used by your team, a better approach is to edit the IAM policies attached to your identities, enforcing permission boundaries when creating/editing other IAM resources (e.g., a developer can create a role only if they also attach a permission boundary to the role - you should also enforce attaching policies only to identities that have the permission boundary set). AWS provides a comprehensive example in their documentation. You can also read more in this blog post.

Refining Permissions

While you could generate policies based on past activities and call it a day, this often causes massive friction. This is why it is important to understand the needs and roles of your team(s). Discuss how your organization uses AWS (i.e., what the main services are), document the deployment process, and ensure you take note of experiments and PoCs you might conduct in the future.

At this point, you can start writing policies based on the requirements you identified and attach them to groups (IAM or SSO groups). For authoring policies, you can consider open-source tools, such as Policy Sentry from Salesforce.

The policies you (or I) write will not be perfect, and the requirements will change over time. Here are the main tools AWS provides to help us refine the permissions:

  • IAM Access Analyzer unused access: we will focus on this below.
  • IAM Access Analyzer policy generation: generate IAM policies based on past activities logged by CloudTrail. Here are some considerations in addition to the ones mentioned in the AWS docs:
    • You can generate policies only for IAM users and roles. IAM groups are not supported.
    • If you are using AWS organizations, you might have a centrally managed CloudTrail trail. When you generate a policy for an identity in a member account, you must grant access to the S3 bucket (and the KMS key) from the account where the trail is configured (which might or might not be the management account).
    • While the AWS console supports only one policy, the CLI supports multiple generated policies. See aws accessanalyzer get-generated-policy.
    • Allocate some time for it. You will most likely need to specify actions for certain services (the ones not mentioned here) and resources for actions supporting resource-level permissions.
  • Access Advisor: Use this to see which services a given identity or group uses. It is also useful when cleaning up policies - it displays the last accessed information across all identities using a given policy. AWS provides some excellent examples. There are several tools that leverage​​ this, such as Netflix's Repokid.
  • AWS CloudTrail: you probably already know it. Here are some considerations:
    • By default, it logs only management events (a.k.a. control plane events).
    • You will need Amazon Athena if you want to query beyond 90 days.

IAM Access Analyzer Unused Access

Remember Access Advisor and the tools built on top of it? Well, IAM Access Analyzer Unused Access is the tool offered by AWS. It was launched in 2023 and became even more powerful with the addition of policy recommendations. It helps you identify unused IAM roles, users (passwords and access keys), and permissions.

Like external access, you must create an unused access analyzer for an account or the entire organization (if you use the management or the delegated admin account). Once created, it will use the last accessed information from Access Advisor in conjunction with an interval you provide (between 1 and 180 days) to determine which identities and permissions are not used.

For identities (users and roles), the next steps are simple: understand why the identity exists (e.g., maybe your team tried to set up continuous deployment using a user and later found out they can and should use an IAM role) and, if it is no longer necessary, delete it.

For unused permissions, the analyzer can provide refined, read-to-use versions of the attached policies.

Note that policy recommendations are not available for users who are part of groups or roles used for IAM Identity Center (i.e., the ones starting with “AWSReservedSSO_”), and if the policy contains notAction (AWS docs). If you were wondering if the recommendations are based on Access Analyzer policy generation behind the scenes, they are not. In fact, the AWS console guides you towards policy generation for the formerly mentioned cases.

Here are a few important facts about IAM Access Analyzer unused access:

  • Analyzers created in the management account are not visible in the delegated admin account. If you have Security Hub enabled in the delegated admin account, you will not see the findings from the management account.
  • You are charged based on the number of identities for each analyzer. Currently, it costs $0.20 per identity (users and roles) per month.
  • For unused access, as opposed to external access, creating the analyzer in one region of your choice is enough (and recommended).
  • You cannot scope down the analyzer to specific identities (if you enable it, it will analyze all roles and users in the given account/organization). (@AWS: This might be a good use case for IAM access paths.)
  • If you use the API/SDK/CLI, you must use ListFindingV2.

Advanced Topics

The mechanisms, services, and guidelines we have discussed so far will help establish a sound IAM posture. If you want even more control, check out the following:

  • Session policies: think of SCP and permission boundaries but applied to a specific role session (i.e., when a principal assumes a role). They enable you to keep a small set of roles while limiting the permissions on a case-by-case basis. Unfortunately, AWS IAM Identity Center does not support them (it does support permission boundaries, though). There is another use case for them: debugging (see this talk).
  • Just-in-time access: if other providers offer this as dedicated services (e.g., Microsoft Entra PIM, Google Cloud PAM - Google also offers an open-source app), Amazon offers TEAM, an open-source solution (built on the mechanisms discussed in this article) you can deploy. Read more in their blog post. And yes, it works with AWS IAM Identity Center.
  • Attributed-based access control (ABAC): support and interest in ABAC have increased in the past few years. Consider it if you are already using tags, if the number of policies is getting out of control, and/or if you have many projects and teams that frequently change.
  • IAM Access Analyzer custom policy checks: if you manage IAM policies through infrastructure as code (IaC), you can integrate them into your pipeline. Custom policy checks should greatly streamline the review of policy changes.
  • Understanding the AWS request signing mechanism (SigV4): We recommend this excellent talk.
  • IAM paths: they look similar to S3 object prefixes but apply to IAM resources. They can help you simplify access management (e.g., you can write a bucket policy allowing access for arn:aws:iam::444455556666:role/teamOrDepartmentPath/* instead of specifying each role).
  • Amazon GuardDuty and Detective: part of the AWS security services suite, these can help you detect and respond to potentially malicious activities. For example, Amazon GuardDuty can detect when credentials are used in anomalous ways (e.g., credentials obtained from an EC2 instance role are used from another IP address), and Amazon Detective can help you gather all the information about an identity (including role chaining).

Cyscale for AWS IAM

Cyscale does not replace any of the features and services covered above, and there would be no point in doing so since they are excellent on their own.

IAM Access Analyzer

AWS IAM Access Analyzer is powerful (and seems to be getting even more powerful) and cost-effective, which is why we recommend it and added support for it. Cyscale guides you in enabling Access Analyzer, provides a cost estimation for Unused Access based on the number of IAM users and roles in your onboarded accounts, helps you identify resources covered by access analyzers, and aggregates the findings.

Access Reviews

While these services and tools help you manage and refine access, this process still has a human element. A common recommendation across providers, guidelines, and compliance frameworks is to perform regular access reviews. Cyscale helps you conduct access reviews by gathering all identities from your cloud environments, linking them to the identity providers, and showing the effective permissions they are granted:

Moreover, you can see all the resources each identity can access:

We sincerely hope you learned something from this article. If you are looking for a simple yet powerful cloud security platform, we would be happy to talk.

Interesting? Share it

Stay Connected

Receive our latest blog posts and product updates.

Our Compliance toolbox

Check out our compliance platform for cloud-native and cloud-first organizations:

CSPM ToolMulti-Cloud Data SecurityGoogle Cloud SecurityAWS Security & ComplianceIAM Cloud SecurityPrevent Cloud Misconfiguration

LATEST ARTICLES

What we’re up to

Your cloud security got safer - Cyscale successfully achieved ISO 27001 certification
AWS IAM: A Comprehensive Guide Toward Least Privilege
Cloud Security Vulnerabilities in Multi-Cloud Environments: Challenges and Best Practices
Cyscale Logo
Cyscale is an agentless cloud-native application protection platform (CNAPP) that automates the contextual analysis of cloud misconfigurations, vulnerabilities, access, and data, to provide an accurate and actionable assessment of risk.

Stay connected

Receive new blog posts and product updates from Cyscale

By clicking Subscribe, I agree to Cyscale’s Privacy Policy


© 2024 Cyscale Limited

crunch base icon
angel icon