Ned
Ned Hello, I'm Nedim, a Cloud Engineer who enjoys writing about technology, particularly focusing on Linux and DevOps. Recently, I've been delving into topics like digital marketing, online presence, and startup culture.

Developer Read-Only AWS IAM Group on AWS Cloud with Terraform

Developer Read-Only AWS IAM Group on AWS Cloud with Terraform

One of the first things I do when setting up a Cloud account on AWS for any client is to set up an IAM group for developers. Most of the time the Developers just need a read-only group that will enable them to access resources but not modify anything. Therefore they need to view logs and easily debug while being restricted not to doing something stupid and accidentally deleting a resource.

Define the Group

Here we define the IAM group.

resource "aws_iam_group" "developer_read_only_group" {
  name = "developer_read_only_group"
}

Attach AWS Managed Policies

Here we attach AWS-managed read-only policies to the previously created IAM group.

data "aws_iam_policy" "developer_read_only_group_policy" {
  for_each = toset(
    [
      "AmazonCloudWatchEvidentlyReadOnlyAccess",
      "AmazonRDSReadOnlyAccess",
      "AWSAppRunnerReadOnlyAccess",
      "AmazonS3ReadOnlyAccess",
      "CloudFrontReadOnlyAccess",
      "AWSCodeBuildReadOnlyAccess",
      "AWSCodePipeline_ReadOnlyAccess",
      "AmazonEC2ReadOnlyAccess",
      "IAMReadOnlyAccess"
    ]
  )
  name = each.value
}

resource "aws_iam_group_policy_attachment" "developer_read_only_group_policy" {
  for_each   = data.aws_iam_policy.developer_read_only_group_policy
  group      = aws_iam_group.developer_read_only_group.name
  policy_arn = each.value.arn

Custom Policy

Here we create a custom IAM policy and attach it to the IAM group. This is where you can add custom permissions to the policies that are not covered by the AWS-managed ones.

data "aws_iam_policy_document" "custom_general_developer_read_only" {
  statement {
    effect = "Allow"
    actions = [
    "s3:ListAllMyBuckets",
      "s3:ListBucketMultipartUploads",
      "s3:GetAccountPublicAccessBlock",
      "s3:GetBucketPublicAccessBlock",
      "s3:GetBucketPolicyStatus",
      "s3:GetBucketAcl",
      "s3:ListAccessPoints"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    effect = "Allow"
    actions = [
      "acm:ListCertificates",
      "cloudfront:GetDistribution",
      "cloudfront:GetStreamingDistribution",
      "cloudfront:GetDistributionConfig",
      "cloudfront:ListDistributions",
      "cloudfront:ListCloudFrontOriginAccessIdentities",
      "cloudfront:CreateInvalidation",
      "cloudfront:GetInvalidation",
      "cloudfront:ListInvalidations"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    effect = "Allow"
    actions = [
    "logs:DescribeLogGroups",
    "logs:FilterLogEvents",
      "logs:DescribeLogGroups"
      "logs:DescribeLogGroups",
      "logs:FilterLogEvents"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    effect = "Allow"
    actions = [
      "ecs:ListClusters",
      "ecs:Describe*",
      "ecs:List*",
      "ecs:ListContainerInstances",
      "ecs:ListTasks",
      "ecs:DescribeClusters",
      "ecs:DescribeClusters"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    effect = "Allow"
    actions = [
      "iam:ListAttachedRolePolicies",
      "iam:ListRoles",
      "iam:ListGroups",
      "iam:ListUsers",
      "iam:GetPolicy",
      "iam:GetPolicyVersion",
      "iam:GetRole"
    ]
    resources = [
      "*"
    ]
  }

}

Here we attach the custom policy to the group.

resource "aws_iam_policy" "custom_general_developer_read_only" {
  name        = "custom_general_developer_read_only"
  path        = "/"
  description = "Allow "
  policy      = data.aws_iam_policy_document.custom_general_developer_read_only.json
}

Here we attach the custom policy to the developer_read_only_group group.

resource "aws_iam_group_policy_attachment" "custom_general_developer_read_only" {
  group      = aws_iam_group.developer_read_only_group.name
  policy_arn = aws_iam_policy.custom_general_developer_read_only.arn
}

User Management

AWS

Now that we have all IAM groups and policies in place we can focus on creating a user and assigning groups to the users.

# Create a User
resource "aws_iam_user" "user_name_created_with_terraform" {
  name = "user_name_created_with_terraform"
}

# Group Membership
resource "aws_iam_user_group_membership" "user_name_created_with_terraform" {
  user = aws_iam_user.user_name_created_with_terraform.name

  groups = [
    aws_iam_group.developer_read_only_group.name
  ]
}

Attach the AWS Change Password Policy

Here we attach the AWS managed change password policy. This will permit the user to change their password.

resource "aws_iam_policy_attachment" "iam_user_change_password_policy_attach" {
  name = "iam_user_change_password_policy_attach"
  users = [
    "aws_username_not_added_by_terraform",
    aws_iam_user.user_name_created_with_terraform.name,
  ]
  policy_arn = "arn:aws:iam::aws:policy/IAMUserChangePassword"
}

Conclusion

In this article, I covered how to create a read-only IAM group with AWS-managed and custom policies, and user management. This is very useful for every Cloud Engineer.

Rating: