Terraform - Reference IAM Policies for an S3 backend

Posted: 19 September, 2021 Category: devops Tagged: awsIAMpermissionsterraform

So while it's tempting to just give the terraform account admin access to everything, it's not a good security policy. It's still worth trying to make the permissions as restrictive as you reasonably can, for this user.

I split up my permissions as follows. The arns etc are examples only and should not be copied verbatim (eg /bucket would be the name of your actual S3 bucket).

AWS IAM terraform S3 backend permissions policy

This is what ended up working for me:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "List",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::bucket"]
    },
    {
      "Sid": "ManageObjects",
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject"],
      "Resource": ["arn:aws:s3:::bucket/*"]
    },
    {
      "Sid": "SpecificTable",
      "Effect": "Allow",
      "Action": ["dynamodb:GetItem", "dynamodb:DeleteItem", "dynamodb:PutItem"],
      "Resource": "arn:aws:dynamodb:*:*:table/xxx"
    }
  ]
}

AWS IAM terraform basic user permissions policy

This is the initial policy I've started with, for provisioning infra via terraform incl compute, databases, and pushing images to ECR:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TerraformCore",
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ec2:*",
        "ecr:BatchCheckLayerAvailability",
        "rds:DeleteDBSubnetGroup",
        "rds:CreateDBInstance",
        "rds:CreateDBSubnetGroup",
        "rds:DeleteDBInstance",
        "rds:DescribeDBSubnetGroups",
        "rds:DescribeDBInstances",
        "rds:ListTagsForResource",
        "rds:ModifyDBInstance",
        "iam:CreateServiceLinkedRole",
        "rds:AddTagsToResource"
      ],
      "Resource": "*"
    },
    {
      "Sid": "PushImagesToECR",
      "Effect": "Allow",
      "Action": "ecr:*",
      "Resource": "arn:aws:ecr:*:*:repository/xxx"
    },
    {
      "Sid": "MaxEC2Size",
      "Effect": "Deny",
      "Action": "ec2:RunInstances",
      "Resource": ["arn:aws:ec2:*:*:instance/*"],
      "Condition": {
        "ForAnyValue:StringNotLike": {
          "ec2:InstanceType": "t2.micro"
        }
      }
    }
  ]
}

... where nnn is your account number and xxx is the relevant resource name. Also obviously modify regions etc as needed. ^ My fave part of the above is not letting this user provision any machines bigger than a t2.micro, lol emoji-laughing We all know AWS LURVES to get paid.

Finally, this is the policy to allow tf to provision an instance profile for a bastion host that needs to be able to connect to other resources (I abandoned this project after this point, so ymmv).

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ConfigureBastionIAM",
      "Effect": "Allow",
      "Action": [
        "iam:CreateRole",
        "iam:GetInstanceProfile",
        "iam:DeletePolicy",
        "iam:DetachRolePolicy",
        "iam:GetRole",
        "iam:AddRoleToInstanceProfile",
        "iam:ListInstanceProfilesForRole",
        "iam:ListAttachedRolePolicies",
        "iam:DeleteRole",
        "iam:TagRole",
        "iam:PassRole",
        "iam:GetPolicyVersion",
        "iam:GetPolicy",
        "iam:CreatePolicyVersion",
        "iam:DeletePolicyVersion",
        "iam:CreateInstanceProfile",
        "iam:DeleteInstanceProfile",
        "iam:ListPolicyVersions",
        "iam:AttachRolePolicy",
        "iam:CreatePolicy",
        "iam:RemoveRoleFromInstanceProfile"
      ],
      "Resource": "*"
    }
  ]
}