Thought leadership from the most innovative tech companies, all in one place.

Creating and attaching an AWS IAM role, with a policy to an EC2 instance using Terraform scripts

This is an infrastructure as a code, which is equivalent to the AWS CloudFormation, that allows the user to create, update, and version any of the Amazon Web Services (AWS) infrastructure. Terraform…

What is Terraform?

This is an infrastructure as a code, which is equivalent to the AWS CloudFormation, that allows the user to create, update, and version any of the Amazon Web Services (AWS) infrastructure.

Why Terraform?

Terraform utilize the cloud provider APIs (Application programming interfaces**)** to provision infrastructure, hence there're no authentication techniques after, what the customer is using with the cloud provider already. This could be considered as one of the best option, in terms of maintainability, security and ease-of-use.

The motivation behind this post is to, illustrate an example of:

  1. creating an AWS IAM role using terraform.
  2. creating an IAM policy using terraform.
  3. attaching the policy to the role using terraform.
  4. creating the IAM instance profile using terraform.
  5. Assigning the IAM role, to an EC2 instance on the fly using terraform.

1. Creating an AWS IAM role using Terraform:

This is where, the IAM role creation will be done. The assume_role_policy parameter is a must to be given within the resource block, and there are other optional parameters as well such as name, path, description etc.

The terraform script:

resource "aws_iam_role" "ec2_s3_access_role" {
  name               = "s3-role"
  assume_role_policy = "${file("assumerolepolicy.json")}"
}

The resource block above, constructs a resource of the stated TYPE (i.e. the initial parameter "aws_iam_role") and NAME (i.e. the second parameter "ec2_s3_access_role"). The integration of the type and name must be distinctive. Within the block (the { }) is the configuration for the resource.

A resource component in terraform, constructs a resource, of the given TYPE (first parameter) and NAME (second parameter) when defining a resource. As an example, if the script is:

resource "aws_iam_instance_profile" "test_profile" { name = "test_profile"
roles = ["${aws_iam_role.ec2_s3_access_role.name}"]
}

So in the above block, aws_iam_instance_profile is the TYPE and test_profile is the NAME. The combination of the type and name must be unique.

assume_role_policy parameter in the above resource block, allows an entity, permission to assume the role.

The assume role policy:

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

2. Creating an AWS IAM policy using Terraform:

This is where we need to define the required policy (i.e. permissions) according to the necessities. For example, allowing the IAM role to access all the S3 buckets within the region. Providing the policy is a required parameter, where as there are other parameters as well such as arn, path, id etc.

The terraform script:

resource "aws_iam_policy" "policy" {
  name        = "test-policy"
  description = "A test policy"
  policy      = "${file("policys3bucket.json")}"
}

The policy parameter in the above block, requires an IAM policy in a JSON format. What the following policy does is that, it allows the IAM role to access all the S3 buckets and also to perform any kind of actions (i.e. list buckets, put objects, delete objects etc.) on those buckets.

The IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": "*"
    }
  ]
}

3. Attaching the policy to the role using Terraform:

This is where, we'll be attaching the policy which we wrote above, to the role we created in the first step.

The terraform script:

resource "aws_iam_policy_attachment" "test-attach" {
  name       = "test-attachment"
  roles      = ["${aws_iam_role.ec2_s3_access_role.name}"]
  policy_arn = "${aws_iam_policy.policy.arn}"
}

The aws_iam_policy_attachment in the above resource block, is used to attach a Managed IAM Policy to user(s), role(s), and/or group(s). But in our case, it was a role. The value for the roles parameter has been accessed from the resource block which we created in step 1.

Value of the role = ${aws_iam_role.ec2_s3_access_role.name}

Explanation:

aws_iam_role is the type of the resource block which we created in step 1.

ec2_s3_access_role is the name of the variable which we defined.

name is a property of that resource block.

The same thing applies to the value for policy_arn.

4. Creating the IAM instance profile using terraform:

This is the resource, which must be used to tag the IAM role to the EC2 instance. As in, when we are creating the resource block for an EC2 instance, in order for us to assign the role to that instance, it expects the aws_iam_instance_profile to be given as a parameter.

The terraform script:

resource "aws_iam_instance_profile" "test_profile" {
  name  = "test_profile"
  roles = ["${aws_iam_role.ec2_s3_access_role.name}"]
}

The value for the roles parameter has been accessed from the resource block which we created in step 1.

5. Assigning the IAM role, to an EC2 instance on the fly using terraform:

Here we will be creating a basic free tier EC2 instance and attaching the iam instance profile which we created above in the step 4.

The terraform script:

resource "aws_instance" "my-test-instance" {
  ami             = "${lookup(var.AmiLinux, var.region)}"
  instance_type   = "t2.micro"
  iam_instance_profile = "${aws_iam_instance_profile.test_profile.name}"

  tags {
    Name = "test-instance"
  }
}

The **tags **parameter is defined to identify or rather differentiate the EC2 instance from the others. It simply represents a mapping. The value of **ami, **is being retrieved from the predefined variables which are defined on a different terraform script as shown below:

variable "region" {
  default = "us-east-1"
}
variable "AmiLinux" {
  type = "map"
  default = {
    us-east-1 = "ami-b73b63a0" # Virginia
  }
  description = "have only added one region"
}

The following commands should be executed from the terminal in the respective order within the directory where the scripts are being saved.

  1. Initializing a new or an existing Terraform configuration

terraform init

  1. Generate and show an execution plan from the resources we're trying to provision

terraform plan

  1. Validating the Terraform files

terraform validate

  1. Builds or changes the infrastructure

terraform apply

The complete list of commands are available here.

Complete source-code is available here for grab:

GitHub - Kulasangar/terraform-demo: Simple terraform scripts to create an iam role and an iam...




Continue Learning