Terraform AWS S3 Bucket backend state and create IAM credentials

I am currently working on refactoring my Terraform configuration for deploying OpenShift 3.11 on AWS. I wanted to share some of the improvements I have made on the configuration by adding AWS S3 as a backend provider and using a custom IAM user for Terraform.

Let’s start with creating an AWS S3 Bucket for the Terraform backend state. You can find information about the Terraform S3 backend provider here: https://www.terraform.io/docs/backends/types/s3.html

First you need to create the S3 bucket on the AWS console:

 

It’s a pretty simple setup and below we see the successfully created S3 bucket:

To use the S3 bucket for the backend state, modify your my main.tf:

terraform {
  backend "s3" {
    bucket = "techbloc-terraform-data"
    key    = "openshift-311"
    region = "eu-west-1"
  }
}

When you run terraform apply it uses the specified S3 bucket to store the backend state and can be used from multiple users.

Instead of using your AWS Root account, it’s  better to create a custom AWS IAM user for Terraform and apply a few limitations for what the user is able to do on AWS.

Go to the AWS IAM service and create a new user with name Terraform. I would strongly recommend using only programmatic access which generates Access Key ID and Secret Access Key.

Create a Terraform IAM user:

In my simple example I created three additional policies to control the access to my AWS subscription:

See the json config for each policy below.

terraform-eu-west-1

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "ec2:Region": "eu-west-1"
                }
            }
        }
    ]
}

terraform-elb

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

terraform-s3

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::techbloc-terraform-data"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::techbloc-terraform-data/openshift-311"
        }
    ]
}

The IAM policies are not very complex, I just wanted to limit the access to a specific region.

The S3 backend provider is very important because I am planning to use Jenkins to deploy the AWS infrastructure with Terraform and storing the backend state locally on the Jenkins server is not very ideal.