12 June 2017

IAM - Identity and Access Management

First service you use when you integrated with AWS is Identity and Access Management (IAM). This service manages permission of users/groups, resources  and services under an AWS account. There are three type of IAM identity and have a relationship like the image:



  • Group - designed permissions for a group of users.
  • User - an identity for a user that work under the same account and grant individual permission or register him to group identities.
  • Role - an identity for a service that work on your behalf. It is called assume role. We must specific a service, a role of another account or external service for a role via "Trust Policy". 

Policy

"Allow someone to take actions on something when it could". This is all to describe a policy statement. There are 2 policy types:
  • identity-based - the policy for IAM roles or users, both of these identities are act as the one who will take action so you can not specific the someone on this policy.
  • resource-based policy - the policy that attach to an service directly. You must specific the someone since it do not know who you are. Unfortunately, not all services support this policy (aws-services-that-work-with-iam)
A policy is defined as a JSON format and contains one or more statements. You can attach one or more policies to an identities too. All policies statements will be combined without ordering no matter what type it is. It follows this rule when a request comes in:
  1. All requests are denied by default
  2. An explicit allow overrides this default. 
  3. An explicit deny overrides any allows.

[Policy Structure]

Allow                      >> Effect         : It can be Allow or Deny
someone                  >> Principal    : Who can do it? It could be either identities or services
to take actions         >> Action        : Actions of the resource you would like to allow
on something          >> Resource    : The full Amazon Resource Name (ARN)
when it could          >> Condition   : The condition of resources or global variables that contains in the request. Operators you can use are vary from resources or variables.
{
  "Version": "2012-10-17",
  "Id": "some-unique-id",
  "Statement": [
    {
      "Sid": "AllowSomeoneTakeActionOnSomethingWhenItCould",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:user/chef",
          "arn:aws:iam::123456789012:role/cooker"
        ]
      },
      "Action": [
        "s3:PutObject",
        "s3:Get*"
      ],
      "Resource": [
        "arn:aws:s3:::pizza-bucket/*"
      ],
      "Condition": [
        "DateGreaterThan": {
          "aws:CurrentTime": "2017-02-28T00:00:00Z"
        }
      ]
    }
  ]
}
Principal: specific the person who can perform on a statement. It can be either identities or services.
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:user/chef",
          "arn:aws:iam::123456789012:role/cooker"
        ]
      }
      "Principal": {
        "Service": "ec2.amazonaws.com"
      }
Action: all actions of each services are difference some actions require permission from other services as well like Simple Systems Manager (SSM), its main work is communicate user requirement to EC2. You need to try it out with reference policies actions document. Most of all services have these three actions, list - list overview of that resource; get - get specific resource from the list; and describe - show inside information of the resource.
      "Action": [
        "[service]:List*",
        "[service]:Get*",
        "[service]:Describe*"
      ]
Resource: they are resources under a service and you specific that resource with the aws arns and namespaces.
      "Resource": [
        "arn:aws:s3:::pizza-bucket/*"
      ]
ARN: you can omit some position on some resources but the safest way is put * in the position that you do not mind what it is.
      arn:aws:[service]:[region]:[account]:resource
      arn:aws:[service]:[region]:[account]:resourceType[/:]resource
      arn:aws:s3:::pizza-bucket/*
      arn:aws:s3:*:*:pizza-bucket/*
      arn:aws:rds:eu-west-1:123456789012:db:mysql-db
Condition: which condition that you would like to allow? You will need some operators for the condition (Operators) and it depends on which resources or variables you are working with.
      "Condition": [
        "DateGreaterThan": {
          "aws:CurrentTime": "2017-02-28T00:00:00Z"
        }
      ]
      "Condition": {
       "StringLike": {
         "s3:prefix": "test*"
        }
      }
Variable: It can be used on any where in the policy like programming language. There are a set of variable that can be applied to Condition which it is not reference to any resource like this list.
      "Condition": [
        "DateGreaterThan": {
          "aws:CurrentTime": "2017-02-28T00:00:00Z"
        }
      ]
      "Resource": "arn:aws:s3:::userbucket/${aws:username}/*"

[Policy Simulator]

You can verify your identities's policies if it will work as you expected on the policy simulator. It is a good tool that can help you guarantee of what you change before apply to the real one and broke everything if it does not work as you expected. It could combine many policies on the simulator if it is in which the same identity. You can put your situation to the resource if you have specific some condition to that resource too. Unfortunately, it supports only identity-base policy and does not combine the resource-base policy when it simulated.

[Examples]

For downloading S3 object
{
      "Sid": "AllowListS3Resources",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::pizza-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": "Hawaiian*"
        }
      }
},
{
      "Sid": "AllowDownloadS3Resources",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::pizza-bucket/Hawaiian/*"

}
For uploading S3 object
{
      "Sid": "AllowUploadS3Resources",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::pizza-bucket/Hawaiian/*"
}
For enabling SSM agent permission
{
      "Sid": "AllowSSMAccessSSMDocument",
      "Effect": "Allow",
      "Action": [
        "ssm:GetDocument",
        "ssm:GetParameters",
        "ssm:ListAssociations",
        "ssm:ListInstanceAssociations",
        "ssm:PutInventory",
        "ssm:UpdateAssociationStatus",
        "ssm:UpdateInstanceAssociationStatus",
        "ssm:UpdateInstanceInformation"
      ],
      "Resource": "*"
},
{
      "Sid": "AllowSSMDescribeEc2",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstanceStatus",
        "ec2:DescribeInstances"
      ],
      "Resource": "*"
}
Finally, it depends on what you design and your company organization to make a good IAM for everyone. I know, same for me too, you want to know some best practices for some resources so you do not go through a lots of AWS documents but as you can see they can be complicated and define in various ways. I would suggest you on a website that you could test on the basic concept of your understanding with each resource at Qwiklabs (https://qwiklabs.com). It guides you n specific resource that you are interesting without to go though a mess of setting to begin on the feature you want to try. You could follow the instruction on your own AWS account if you do not want to pay more to the Qwiklabs.