AWS Authentication and Authorization with Policies
Tags: aws, beginners
Published: 2020-08-26 20:10:42

In a previous post on in the AWS 101 series, I covered some details on __Identity and Access Management__ and touched on IAM policies. In this blog, I will be expanding on the concept of policies and how they are used to authorize identities, whether human users or applications, to perform actions in an AWS account.

# Authentication

Understanding how authentication happens in AWS is not critical but is interesting to know and offers some insight when attempting to write good policies. Whether you are using the console, CLI or SDK, the authentication is handled by AWS.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ao2eyz36ukjhvv4mbe6v.png)

In the above diagram, we have a principal or identity attempting to make a call to the S3 service. The attempted action is a listing on an object in a bucket using the ListObjects API call. Like everything else in AWS, this call will be authenticated and authorized. It’s a role, so it will have short term credentials. If we look at the output generated by the debug flag on the CLI command, we can see the role that is providing the credentials for the call.

This role happens to be called __S3ReadOnlyForEC2__. Next, you can see the bucket endpoint. In this case, the bucket is in af-south-1. Then further down, you will notice the __Credential__ header. The first part of this header is the Access Key ID. This is passed in the clear because there is nothing secret about it. The secret part is the secret access key. The Access key ID is an identifier for the caller of this API call and the principal they claim to be. They have not proven it yet, but it’s who they claim to be.

Lastly, is the __Signature__. The signature is an HMAC signature and is produced client side with the secret access key that belongs to the session since the identity is a role. The crucial parts of the API call were signed and if this signature is validated by AWS, it means that the call was definitely made by the principal and the contents of the call has not been meddled with. Essentially proving the principal’s identity.

Proving the identities validity is only the first part of the process. The next step is whether the identity actually has permissions to make this call. This is where __Policies__ come into play.

# Authorization with Policies

Unlike authentication, which is handled mostly by AWS, it’s important to understand how policy authorization works. Authorization is understood to be extremely literal.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zsgswbls595if57tq5kv.png)

The above basic graphic indicates how policies decide the authorization status of a principal. In this example it can be assumed the principal has successfully authenticated. Policies will now decide whether the desired action to the S3 service can be fulfilled. There will be a number of policies associated to the request. Some will be associated with the principle making the call, some possibly with the resource or service and some with a number of other things.

These policies will contain several statements. There could be statements that relate to services other than the one in question and these statements can be considered irrelevant. The policies will be evaluated, and determinations will be made as to which are relevant and which are not. Once the relevant statements have been determined, each one will either allow or deny.

The overall rule is simple: __a policy must allow, and no policy must deny. If no policy claims the request, it’s denied__. In AWS, one needs permission to execute any action, otherwise you will not be able to. In the above example, the policy on the left is relevant and is allowing the request. The policy on the right is also relevant but it is denying the request. Hence, the overall judgement on authorization will be deny.

# Reading and Writing IAM Policy

Understanding the literal nature of IAM policies is best shown by example. The example we will be looking at is one that represents an application running on EC2 and connecting to DynamoDB. The EC2 instance has a role associated to it. We want to give the role permission to read and write to DynamoDB. Let see the different options available to us and which option is the most effective in regard to the principle of least privilege.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/alrpdng00id8dijdvbqe.png)

We could write a policy like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pmtmm4jt6yt7dqlnvr3d.png)

This policy will definitely work by allowing all actions. But this can be considered a bad policy for the requirements of the application. This policy is akin to full administrative permissions and provides way too many actions that this application will probably ever need and introduces risk into the equation. We could improve the policy by doing this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v7ii86b01ushnwzsu453.png)

This policy is a slight improvement, since it limits the actions to the dynamodb service. But it allows all actions to the service and to all resources related to the service. The policy is still unacceptable since it still allows too much permission for the purpose of the application. Let’s keep improving the policy. What if we tried this?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/upogwohmmsak6e3t0v6q.png)

This is a vast improvement because it states specific actions. Like all the services on AWS, dynamodb has many API’s associated with it. There are API’s that can delete tables, provision tables etc. However, we know that this application only needs to read and write to the tables. So those are the only API actions that should be allowed. What about the resource field of the policy? It’s not ideal. How can we do better?
 
To write an optimal policy, one should become familiar with the looking up the service details on the IAM policy reference page.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mtqyzsr16lxdslakwhpj.png)

On the page you will see a link called "Actions, Resources, and Condition Keys for AWS Services". This page will show a list of each and every AWS service. You can then select the service you are attempting to write a policy for. In our case we will choose Amazon DynamoDB. You will be presented with a structured table to show you how to write the policy.

One of our actions were GetItems, so below is the row that describes this action.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1xx2vac9nvudyzmpessu.png)

You will notice that the resource type that applies is a table. This implies that with this action, one can authorize specific tables. How do we apply this to the resource field in the policy?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7egqw2exkgd28g27f8ya.png)

Notice the string that now appears in the resource field. This is called an __Amazon Resource Name (ARN)__. Each resource on AWS has an ARN and they are all formatted in the same fashion. After "arn:aws", the ARN takes the format of: the name of the service, the region, the aws account number and then the service specific part. This uniquely identifies the resource across all of AWS. How does one get the ARN for this specific resource? Once again, let’s look at the documentation. If one clicks on "table*" in the Resource Types column in the above table your will be presented with a page that lists the "__Resource Types Defined by Amazon DynamoDB__"

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7z11nv53kuqrc4mgpxni.png)

This will show you the format that the ARN needs to take to comply with the resource that the policy requires. The full policy will now look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/iu1vazuf9op90zmxv6uy.png)

The policy now has specific actions of reading and writing and a specific resource of a dynamo table. It follows the principle of least privilege and will match the request with the exact requirements and can be considered the optimum policy for the applications requirements. It should be noted that policies can be more complex than this, with additional attributes. For this example we've chosen a simple policy for the purpose of illustration. The reader is encouraged to further explore policies.

# Conclusion

Authorization practices in AWS should always follow the principle of least privilege. IAM policies are designed in such a way to achieve just this. If configured correctly, one can rest assured that the manner in which services are accessed by principals, whether human or machine, are always done in the most secure manner possible. As always, any feedback is encouraged.