IAM roles for CloudFormation install

Setting up role/policies required for installation using CloudFormation.

Role

An IAM role is needed for CloudFormation to assume and to execute the BootstrapLambda Lambda function because BootstrapLambda applies some Kubernetes resources to the EKS cluster, and initially, only the IAM entity that created the EKS cluster has authorization.

This IAM role’s assume role policy document should resemble:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"Service": "cloudformation.amazonaws.com"},
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {"Service": "lambda.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }
  ]
}

If you want to be able to use kubectl on the cluster, you can follow the instructions here. Initially, you will likely need to add one user to the above assume role policy document’s Statement list; the entry will resemble:

  {
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::90000:user/john-doe"},
    "Action": "sts:AssumeRole"
  }

Remember to use the --role-arn option when calling aws eks update-kubeconfig as a user that that needs to assume created IAM role.

Role policy

A starting point for a managed policy document that you can attach to the IAM role is:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:AddRoleToInstanceProfile",
        "iam:AttachRolePolicy",
        "iam:CreateInstanceProfile",
        "iam:CreateRole",
        "iam:DeleteInstanceProfile",
        "iam:DeleteRole",
        "iam:DetachRolePolicy",
        "iam:GetInstanceProfile",
        "iam:GetRole",
        "iam:PassRole",
        "iam:RemoveRoleFromInstanceProfile"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["ec2:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["elasticloadbalancing:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["route53:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["eks:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["autoscaling:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["cloudformation:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["lambda:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:*"
      ],
      "Resource": "*"
    }
  ]
}

You might want to avoid using * for some of the Resource entries and specify exact resource ARNs or ARN prefixes depending on how you name the resources.

Explanation of service permissions needed:

  • logs: A Lambda function (BootstrapLambda) is created and invoked, and will log to CloudWatch.
  • iam:*: The template creates a service role for the EKS cluster and creates an instance role and profile for the EC2 instances in the Auto Scaling Group.
  • ec2:*: The template creates a VPC, subnets, security groups, Elastic IPs, and related resources.
  • elasticloadbalancing:*: The template creates load balancers.
  • route53:*: The template creates DNS records for the load balancers.
  • eks:*: The template creates an EKS cluster.
  • autoscaling:*: The template creates an EC2 Auto Scaling Group to serve as worker nodes in the cluster.
  • cloudformation:*: The main template declares nested stacks.
  • lambda:*: The template declares a Lambda function to perform tasks that native CloudFormation resources aren’t able to, such as copying Replicated-related files to the nodes and declaring Kubernetes resources.
  • ecr:*: The template declares ECR repositories required for running Bugsnag.