Generating Policies with AWS IAM Access Analyzer

AWS IAM Access Analyzer

In this blog post we will do the following:

  • Define AWS IAM Access Analyzer
  • Deploy AWS IAM Access Analyzer via Terraform
  • Explain Findings and how to respond to them
  • Generate a policy based on activity of an IAM user

What is the AWS IAM Access Analyzer?

AWS IAM Access Analyzer provides the following capabilities:

  • IAM Access Analyzer helps identify resources in your organization and accounts that are shared with an external entity.
  • IAM Access Analyzer validates IAM policies against policy grammar and best practices.
  • IAM Access Analyzer generates IAM policies based on access activity in your AWS CloudTrail logs.

https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html

In essence it allows you to resolve IAM access issues in a effort to enforce least privilege.

 

Why use AWS IAM Access Analyzer

The AWS IAM Access Analyzer provides tool provides you with the ability to identify resources that are shared with an external identity. The tool can then provide recommendations for modifications to IAM policies to ensure this access is following least privilege.
 

Configuring AWS IAM Access Analyzer with Terraform

There are four resource providers you will use for deploying the IAM Access Analyzer:

In this post we will enable IAM Access Analyzer with Terraform, analyze some founds and modify IAM Policy permissions based on the recommendations.

The first thing we start with Terraform is our providers. I prefer to separate those out into their own file. In this case we are utilizing the aws module and we are saying we want version 4.50.0. 

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "4.50.0"
    }
  }
}

This code block has the actual resource provider needed for our deployment. In this example we are using aws_accessanalyzer_analyzeraws_iam_policyaws_iam_role, and aws_am_role_policy_attachement. You will need to specify a name next to analyzer_name. In addition I have provided an option if you would like to deploy this at the AWS Organizations level, this section has been commented out but feel free to uncomment and use this instead.

resource "aws_accessanalyzer_analyzer" "iam_aa" {
  analyzer_name = "${var.env}_iam_aa"
}

resource "aws_iam_policy" "iam_aa_policy" {
  name        = "${var.env}_iam_aa_policy"
  description = "Policy to enable AWS IAM Access Analyzer to access CloudTrail logs on ${var.env}"

policy = <<POLICY
{
"Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "cloudtrail:GetTrail",
      "Resource": "*"
    },
    {
        "Effect": "Allow",
        "Action": [
          "iam:GenerateServiceLastAccessedDetails",
          "iam:GetServiceLastAccessedDetails"
        ],
          "Resource": "*"
    },
    {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject",
            "s3:ListBucket"
          ],
          "Resource": [
              "arn:aws:s3:::${var.cloudtrail}",
              "arn:aws:s3:::${var.cloudtrail}/*"
          ]
    },
    {
          "Effect": "Allow",
          "Action": [
            "kms:Decrypt"
          ],
          "Resource": [
            "arn:aws:kms:${var.ctkey}"
          ],
          "Condition": {
            "StringLike": {
              "kms:ViaService": "s3.*.amazonaws.com"
        }
      }
    }
  ]
}
POLICY
}

resource "aws_iam_role" "iam_aa_role" {
  name = "${var.env}_iam_aa_role"
  path = "/service-role/"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "access-analyzer.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

  tags = {
    Name = "IAM Role for AWS IAM Access Analyzer to Read CloudTrail Logs"
    Environment = var.env
  }

}

resource "aws_iam_role_policy_attachment" "iam_aa_role_policy_attachement" {
  role       = aws_iam_role.iam_aa_role.name
  policy_arn = aws_iam_policy.iam_aa_policy.arn
}

# resource "aws_organizations_organization" "aws_org" {
#   aws_service_access_principals = ["access-analyzer.amazonaws.com"]
# }

# resource "aws_accessanalyzer_analyzer" "org_iam_aa" {
#   depends_on = [aws_organizations_organization.aws_org]

#   analyzer_name = "${var.env}_org_iam_aa"
#   type          = "ORGANIZATION"
# }

Our final code block is for variables, we have three variables. “env” is for the name of your environment which helps with naming. “cloudtrail” is the S3 bucket name that your CloudTrail is using. “ctkey” is the KMS key use for CloudTrail encryption if you are using this, it’s in the format of us-east-1:accountid:key/kmskeyidhere.

variable "env" {
  type    = string
  default = "prod"
}

variable "cloudtrail" {
  type = string
  default = "mycloudtrailgoeshere"
}

variable "ctkey" {
  type = string
  default = "mykmskeyforcloudtrailgoeshere"
}

After you run your terraform apply you will end up with AWS IAM Access Analyzer deployed with the additional rights need to generate policies.

Reviewing Findings and Remediating

Once you login to the AWS admin console, browse to IAM and then Access Analyzer you will see the analzyer created earlier. Under ‘Active findings’ you will see a list of current findings. The findings are sorted into four columns which are fairly self explanatory. The finding itself has seven pieces of metadata as follows:
  • Finding ID – This is the automatically generated finding identifier created when a finding is created, this is a clickable link to get more information on the finding.
  • Resource – This is the resource that permissions were assigned to.
  • External Principal – This is the external principal that has permissions to the resource. This can be ‘AWS account’, ‘Any principal’, ‘Canonical user’, ‘IAM role’ or ‘IAM user’.
  • Condition – This is the condition from the policy statement that grants access.
  • Shared through – This indicates how the finding is generated such as ‘Bucket policy’, ‘Access control list’, or ‘Access point’.
  • Access level – This indicates the level of access granted to the external identity.
  • Updated – This will show you when the finding was generated or the last time it was updated.
 
Clicking a finding will open a page that shows the same data summarized here with some items expanded such as Access level. At the bottom of the page under ‘Next steps’ you have two categories ‘Intended access’ and ‘Not intended’. If the the finding is expected you can click ‘Archive’ but if the access is not intended you can click link to the service in question, in this example ‘Go to S3 console’. You can then remediate the access issues.
 

Generating an IAM Policy Based on Activity (CloudTrail Events)

In this section we will be generating a least privilege IAM policy based on current activity. In my example we have a user ‘jeremyredmond’ who has full Administrator access but they are only creating S3 buckets. We will generate a policy based on CloudTrail events.

  1. Log into the AWS admin console.
  2. Browse to IAM and select the user you would like to modify the access for.
  3. Select ‘Generate policy’ at the bottom of the page.

4. Select your time period, in this example we are using last 1 day however you will probably want a longer period.

5. Select your CloudTrail trail.

6. Specify the regions you would like this to apply to, in this case we have selected ‘All regions’.

7. Select ‘Use and existing service role’ and select the role that we created earlier through Terraform.

8. Click ‘Generate policy’.

9. The process may take a few minutes to complete, once the status changes to ‘Success’ click ‘View generated policy’.

10. The report will show the minimum (least privilege) permissions required based on the activity. 

11. In addition you can modify permissions manually for each service that was used. Click ‘Next’.

12. Review the JSON statement for the new policy and modify where needed. You may need to manually resolve some of the errors such as region locations. Click ‘Next’ once completed.

13. Give your policy a name and description and click ‘Generate and attach policy’.

14. You now have an updated policy attached to your user with least privilege access. Remove the old policy or group.

You can find the Terraform files in my GitHub repository here:

https://github.com/jsredmond/aws-iam-access-analyzer

More to explore

Leave a Reply

Your email address will not be published. Required fields are marked *