AWS IAM deep dive: How IAM users and groups work

How to give Console and programmatic access to the AWS account

Author's image
Tamás Sallai
9 mins

IAM users are the essential building blocks when an AWS account is used by more than one person. They provide people inside the organization a way to log in to the management Console and manage resources and also to use the AWS APIs with access keys.

In this article, we'll look into how users can access an account, and how to define what they are allowed to do.


Users are access points to the AWS account. They are usually associated with a person who needs access to do his duties. Creating a separate user for everybody is a good security practice, not only because it prevents the sharing of secrets (passwords and access keys) but also that it allows seeing who did what in an after-the-incident investigation.

Every IAM user has a username and a set of permissions in the form of IAM policies. When they log in they also need to know the account id, so that they are namespaced between accounts.

IAM users signin link

Users can interact with the account in two ways: using the Console and through APIs (and SDKs). To use either of them, a user needs a secret. Signing in to the Console requires a password while using the APIs require access keys.

When you create a new user, you need to select which of these accesses you want to provide initially. You can change it for existing users too.

Create user dialog

New users usually start with Console access as that provides insight into what is going on inside the account and offers forms to manipulate and create resources. But everything that can be done on the Console can be done through the APIs too.

Access Keys

An access key is equivalent to a password but for the AWS APIs. These APIs have the same capabilities as the Console, so everything you can do by logging in you can also do programmatically (and more, in some cases).

The access keys for a user are listed on the Security Credentials tab:

Security credentials on the IAM user page

You'll see a list of access keys and a button to create a new one:

Create access key button on the IAM user page

An access key consists of two parts: an Access key ID and a Secret access key. You'll see both when the key is created:

A generated access key

And the list shows the newly created key:

Access keys for a user

A user can have 2 access keys at a time and they both provide identical access to the account. To rotate a key, create a new one, update the systems wherever it is embedded, then delete the old one.

The primary use case for access keys is to use the AWS CLI to manage the account using the command line. It supports the credentials file that stores the keys. To add the access keys to a CLI configuration, use aws configure, then copy-paste the keys:

$ aws configure
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: 
Default output format [None]: 

Then whenever you issue a command, it picks up these credentials and uses the access of the user:

aws s3 ls

Most tools that build on AWS APIs support this location too. Terraform will work when the AWS CLI is configured, and also SDKs will pick up the credentials from there.

Alternatively, you can use environment variables to overwrite the config file. Set the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and clear the AWS_SESSION_TOKEN when you issue the command:

	aws s3 ls

Note that the credentials file, located at ~/.aws/credentials, contains the keys in plain text. Whoever has access to this file can copy them and have access to the account in the name of the user. Because of this, access keys are different than passwords which are only known by the users.

Everything the user does is subject to IAM policies, and it includes everything done with the access keys. You can even require MFA authentication via policies.

The access key is comprised of 2 parts: the Access key ID and the Secret access key. The former identifies the account and the user and it is not secret. Whenever there is a request to AWS, it is included in it in plain text.

The Secret access key, on the other hand, is secret. It is only used to calculate a signature for a request made with an access key and it can not be recovered by observing what is going on the wire.

Password-based login

When users want to log in to the Console they need to use their passwords if they have one. A best practice is to let the users manage their own secrets, which means an administrator should only set the initial password and force change on the first login.

Use an autogenerated password and force reset on first login

But users might choose a password that is not secure enough, and there is little administrator oversight over it. An account-wide password policy helps by requiring certain character classes (lowercase, uppercase, numbers, special characters) and rotation.

Password policy elements

When a user has an MFA device attached it is also required during the sign-in process. You don't need policies to enforce it, contrary to API access.

Natural and technical users

There is only one kind of IAM user in AWS but conceptionally we can distinguish two distinct usages. Natural users are tied to a person and gives access to the account. This type of user usually needs Console access and a wider range of permissions.

Then there are technical users to provide a non-AWS service access to some protected resource in the account. Because it is for a specific step in a workflow, the permissions can be locked down, usually just to one action on one resource.

For example, you might have some script running in the Google cloud that needs to publish a message to an SNS topic. You can deploy a Lambda function behind a public API Gateway to publish these messages, or you can create a technical user, generate an access key, and embed that into the script.

For services inside AWS, you don't need users as those support roles to get access to the account.


What users can do inside the account is controlled by IAM policies. For example, you can give read access to objects in a specific bucket:

	"Version": "2012-10-17",
	"Statement": [
			"Action": [
			"Effect": "Allow",
			"Resource": "arn:aws:s3:::<bucket>/text.txt"

When a policy is attached to a user, a group, or a role it is called an identity-based policy. These policies define what the identity can do, as opposed to resource-based ones that control access from the resource-side. As a rule of thumb, when you create a new IAM user it has no access to the account and you need to attach policies to selectively grant permissions.

IAM policies allow fine-grained control but that requires careful fine-tuning and a familiarity with the services you want to give access to. AWS provides a set of managed policies that allows a range spanning from Administrator down to read/write for individual services. These are great to get started as you don't need to touch JSON. But if you want to move to a finer granularity, such as allow reading from a specific bucket, you need to get familiar with the policy language.

The goal of policies is to define the least privilege where everything the user needs is allowed but nothing else. This reduces the blast radius, the impact of a breach, to the minimum without hindering the users to perform their work. But, in practice, permissions tend to accumulate over time as it's the more urgent problem to solve when someone is lacking access to a resource.


Groups implement the Role-based access control (RBAC) scheme where users are assigned into groups and only these groups get permissions. What each user can do is then determined by membership instead of individual policies.

Don't confuse the naming here. A role inside AWS is an entirely different concept.

This access-control mechanism simplifies permissions when you have a lot of similar users in the account. If you attach policies to each of them individually you'll end up with a lot of silos and you need to keep all of them up-to-date to prevent unneeded permissions. If you create groups and assign users to them you'll have a lot fewer identities and policies to maintain.

As a best practice, use groups and only give access to them instead of individual users. This allows easier scaling when a department is expanding as you only need to create a user and assign it to the group. When somebody moves to a new role inside the organization, you can reassign the memberships and that reassigns the permissions too.


IAM users provide an entry point to the account, either by having a password to sign in to the Console or using access keys to use the AWS APIs. They can be for natural persons to do their jobs or embedded into a third-party system to give programmatic access to the account.

IAM policies attached to users control what permissions they have. The granularity can range from full access down to just a single action on a single resource.

Groups allow assigning permissions to a set of users. Instead of managing policies for each user individually, you can create groups and define access through membership.

October 9, 2020

Free PDF guide

Sign up to our newsletter and download the "Foreign key constraints in DynamoDB" guide.

In this article