AWS Security from Day 1 with IAM

Part 3 of the Complete AWS Boilerplate

Kangzeroo
11 min readJan 17, 2019

This is the third tutorial in the series “The Complete AWS Boilerplate” for quickly building entire internet products on the Amazon Cloud.

Welcome back to The Complete AWS Boilerplate. Today we’re going to dive deeper into security with IAM (Identity Access Management). The pre-requisite for this tutorial is Part 1 where we go over the process of creating a new user account for IAM. Click here if you haven’t read that yet.

To re-emphasis, security is something that should be considered from Day 1. It is much easier to build your infrastructure with security in mind than it is to audit and update your infrastructure to be secure later.

To begin, login to your “Root Admin” account on the AWS Console. We are going to create a new admin account called “CTO”, which will be used for all our future logins. We will also set up some user groups for various teams in our organization. Before we begin, let’s go through some concepts.

Don’t worry about understanding the below diagram yet. We will revisit this at the end of this tutorial.

The Hierarchy of Permissions — How Users or AWS Resources get authorization

Basic Security Concepts

Web security is a huge domain involving many topics. In this article we will only go over IAM security (related to user accounts & permissions):

  • User Groups
  • Users
  • Roles
  • Policies
  • Multi-Factor Authentication

Various teams across your organization should have specific access to specific AWS resources. For example, your Sales Team needs to be able to view data but not modify it. Your full-time programmers should be able to make changes wherever needed, but interns should not (lest they delete a database in production). Subcontractors should only be able to touch the parts they’re hired for. You get the idea.

So let’s actually do this in our IAM console. We will start by making a User Group called “Business Analysts” which are allowed read-access to all DynamoDB tables

DynamoDB is useful for many things, such as storing historical transactions of product purchases. We will cover DynamoDB in another article, but for now all you need to know is that our Business Analysts will use it to find data relevant to their job tasks

User Groups

Go to IAM and click the “Groups” tab and click “Create New Group”.

We’re going to call it Business-Analysts.

Now we can attach policies to our group. Policies are just rules that specify who can access what. The what can be an S3 bucket or any other AWS resource. The who can be a user (such as an intern or the CTO), but it can also be an AWS resource. How is this possible? Because AWS allows resources to trigger jobs to be done. For example, we can trigger an S3 bucket to run an image compression script any time a new JPG or PNG file is added to the bucket. That script is also an AWS resource, and we would have to create a custom IAM policy to let our S3 bucket access that script. We will make a custom IAM policy later in this tutorial for allowing MFA (multi-factor authentication).

For now, let’s continue attaching our user policy.

Search for the policy AmazonDynamoDBReadOnlyAccess and check it. Add any others if you want.

Notice that if we click the “Policy Type” dropdown, we can see that these policies can be filtered into “AWS Managed” and “Customer Managed”. There are policies that come default with AWS and there are custom policies we can make ourselves (which we will learn in the MFA section of this tutorial).

Let’s continue on to the next step, Review.

If everything is good, let’s click “Create Group”.

Now let’s create another group called “Developers”.

Except this time we’re going to set the “Policy Type” to “Job Function”. This gives us a list of common job functions with pre-defined policies. We’re going to use PowerUserAccess which grants read+write access to all AWS resources except for modifying IAM. Now we have 2 groups as seen in the screenshot below.

Creating Users

The next thing we will do is create a CTO user. Click the “Users” tab and “Add User”.

I plan on giving the CTO admin access to everything in the AWS Console including the ability to modify IAM. We’re going to only give AWS Console access and NOT programmatic access because programmatic access is too risky for an admin account. Imagine a hacker who got access to your CTO credentials with programmatic access. A script could easily delete/steal everything in your cloud in minutes, whereas interacting with a graphical interface is fundamentally slower. Furthermore, with MFA the hacker would also need your phone to enter the AWS console.

Click “Next” when you’re ready.

Now we can add the CTO to the “Developers” group. We’re also going to attach a policy directly.

Click the “Attach Existing Policies Directly” tab and select AdminstratorAccess to make everything accessible, including IAM. When you are done, go back to the “Users” tab and click into the CTO user.

Then click “Security Credentials”.

Click that URL link in “Summary” and login with your new CTO account. It’s the same as the Root Admin you’re currently using, but better for logging (AWS automatically logs who made what changes, so the CTO account can be directly tied to someone in your organization).

The below diagram shows how a user can inherit policies via IAM roles. Note that users can also have IAM policies attached directly without an IAM role.

AWS lets us get very granular with permissions (very necessary for Enterprise scale). Roles are used to group policies, and users can assume multiple roles.

Users can also assume policies from groups:

The above diagrams may seem confusing, so let’s bring back this humble diagram that explains the same IAM relationships:

Remember that a User can also be an AWS resource such as an S3 bucket

Setting a Password Policy

For further security, we can require users to have complex passwords that periodically change. Go to the IAM dashboard and open “Apply an IAM password policy” from the Security Status checklist and click “Manage Password Policy”.

You can choose to make your passwords as simple or complex as you want.

Setting Up Multi-Factor Authentication (MFA)

Finally we get to MFA. It’s called Multi-Factor Authentication because you have an additional login requirement beyond your password (the first “factor” to authentication). MFA is usually time and device based, such as a SMS text message sent to your phone that expires in 10 minutes. A hacker with your password can’t login unless they also have your phone. This extra layer of security is what we will be setting up on your smartphone for all user logins. So let’s begin at the IAM dashboard.

At first, we are unable to activate MFA. If we click “Learn More” we are taken to this page here, which tells us we must add an IAM policy to allow MFA.

Creating Custom Policies

Simply copy to your clipboard the below IAM policy (represented as a JSON file).

{     "Version": "2012-10-17",     "Statement": [         {             "Sid": "AllowListActions",             "Effect": "Allow",             "Action": [                 "iam:ListUsers",                 "iam:ListVirtualMFADevices"             ],             "Resource": "*"         },         {             "Sid": "AllowIndividualUserToListOnlyTheirOwnMFA",             "Effect": "Allow",             "Action": [                 "iam:ListMFADevices"             ],             "Resource": [                 "arn:aws:iam::*:mfa/*",                 "arn:aws:iam::*:user/${aws:username}"             ]         },         {             "Sid": "AllowIndividualUserToManageTheirOwnMFA",             "Effect": "Allow",             "Action": [                 "iam:CreateVirtualMFADevice",                 "iam:DeleteVirtualMFADevice",                 "iam:EnableMFADevice",                 "iam:ResyncMFADevice"             ],             "Resource": [                 "arn:aws:iam::*:mfa/${aws:username}",                 "arn:aws:iam::*:user/${aws:username}"             ]         },         {             "Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",             "Effect": "Allow",             "Action": [                 "iam:DeactivateMFADevice"             ],             "Resource": [                 "arn:aws:iam::*:mfa/${aws:username}",                 "arn:aws:iam::*:user/${aws:username}"             ],             "Condition": {                 "Bool": {                     "aws:MultiFactorAuthPresent": "true"                 }             }         },         {             "Sid": "BlockMostAccessUnlessSignedInWithMFA",             "Effect": "Deny",             "NotAction": [                 "iam:CreateVirtualMFADevice",                 "iam:EnableMFADevice",                 "iam:ListMFADevices",                 "iam:ListUsers",                 "iam:ListVirtualMFADevices",                 "iam:ResyncMFADevice"             ],             "Resource": "*",             "Condition": {                 "BoolIfExists": {                     "aws:MultiFactorAuthPresent": "false"                 }             }         }     ] }

Now let’s go back to our CTO user and click “Add Permissions” button in the “Permissions” tab.

Click the tab “Attach Existing Policies Directly” and the button “Create policy”.

A new tab will appear where you can create a policy as a JSON file. Paste in the JSON text from earlier. Now this next step is very important. In the JSON, replace all instances of ${aws:username} with your username (in this case it would be CTO).

Before we continue, let’s take this opportunity to examine the structure of this IAM policy. The first layer of this JSON file is version: date string and structure: array. We can use version to maintain versioning of our IAM file (necessary for large Enterprises). More interesting is structure, which are the rules that make up this policy. Let’s examine one of the rules inside the structure array.

{
"Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/CTO",
"arn:aws:iam::*:user/CTO"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}

Sid is the unique id to identify this rule.

Effect is what we want to do with this rule (in this case it is Allow an action, but it can also be Deny).

The Action is what can be done, which is an array of possibilities. In the above example, it is allowing the deactivation of a MFA device (A MFA device is one that acts as secondary verification of your identity. A common one is when you get a 4-digit PIN sent as a text message sent to your phone). Notice that the deactivation rule is called “iam:DeactivateMFADevice”. This is not randomly named, there are a list of IAM actions for everything. You can see that list here.

The Resource refers to the AWS resources that this rule affects. So when we Allow iam:DeactivateMFADevice on arn:aws:iam::*:mfa/CTO and arn:aws:iam::*:user/CTO we are allowing the CTO user to deactivate the CTO’s multi-factor authentication. Resources always use an ARN (Amazon Resource Number), which is a unique identifier for that AWS resource. You can also add wildcards to a statement such as arn:aws:iam::*:mfa/* which would let our CTO user be able to deactivate any user’s MFA.

The Condition is used for safety checks on resources before allowing an action. In this case, we can only attempt to iam:DeactivateMFADevice if aws:MultiFactorAuthPresent is true. To see the full list of conditional statements, click here.

Ok, now let’s finish up this custom policy by clicking “Review Policy”, giving it a title of “Allow-MFA-CTO” (multi-factor authentication), and click “Create Policy”.

We will be brought back to the list of IAM policies. Go back to the tab for adding permissions to our user and click the refresh button at the top right hand corner. Then search for “Allow-MFA” and click “Next:Review” and verify that you want to create the policy.

You will be brought back to the user screen and should see the new IAM policy added to our user.

Now if we click back to the “Dashboard” tab in IAM, we will get a lot of red. What is happening??

Well if we look back at the IAM policy we created, one of the rules has an Sid called BlockMostAccessUnlessSignedInWithMFA. Our current user’s login session did not sign in with MFA, which is why so many things are blocked. But we also have not yet set up a MFA device, so our current user is essentially useless. We need to log out and log back in with our Root Adminstrator account.

Login at https://console.aws.amazon.com/

After logging back in with our Root Adminstrator account, go back to the IAM dashboard to the “Users” tab and click the CTO user we created. Go to the “Security Credentials” tab and click “Manage” beside “Assigned MFA device”.

Select “Virtual MFA device”.

On this next screen, click “Show QR Code”

Now you will need to download a smartphone app for MFA. Your options are Google Authenticator or Authy (I use Authy). Both links contain tutorials for setup. It takes less than 5 minutes and once you scan the QR code you’re done! Once you’ve successfully scanned the QR code, enter 2 consecutive MFA codes shown on your smartphone and click “Assign MFA”. And that’s all there is!

You’re also going to want to do this for your Root Adminstrator account, so go back to the IAM dashboard.

Let’s finish up that final to-do in our Security Status. Click “Manage MFA” and in the pop-up click “Continue to Security Credentials”.

Repeat the same MFA setup process for the Root Administrator and we are finally done the Security Setup! Doesn’t this look wonderful?

😍 Wonderful

Now if we log out of Root Adminstrator and back into our CTO user, we will be asked to enter the MFA code.

Simply enter it in and you’re done!

Congratulations! You now understand IAM and have a secure AWS Cloud from Day 1!

Review

In this tutorial we learned:

  • The relationship between Policies, Roles, Users and Groups
  • How to create a group and assign users to it
  • How to create a role and assign it to a user
  • How to create a user
  • How to create and read an IAM policy in JSON format
  • How to setup Multi-Factor Authentication

See you on the next tutorial!

--

--