/terraform-session-token

Native AWS Multi Factor Authentication for standard Terraform

Primary LanguagePythonGNU General Public License v3.0GPL-3.0

Terraform Session Token (MFA)

A small AWS Multi Factor Authentication tool to create a session token for an assumed role and updates the AWS credentials file for Terraform.

Why?

The standard version of Terraform currently has no means of MFA support with AWS. Terraform on execution will attempt a number way to find AWS API keys. Unfortunately when you define a profile for AWS CLI MFA in the credentials file, no keys are actually defined so Terraform can't use this setup. Terraform Session Token allows access keys to have least priviledge access, and Terraform is able to perform it's duties safely with MFA.

Getting Started

Using 'terraform-session-token.py' the default profile is used only for assuming an elevated access role, which has a condition that MFA must be supplied. Once Authenticated session token details are placed into the credentials for use by Terraform that are valid for an hour, however this can be increased or decreased.

Prequisities

What things you will need to install and configure

Installation

Clone the repository or download the 'terraform-session-token.py' onto your system.

git clone https://github.com/johnbrandborg/terraform-session-token.git

Usage

terraform-session-token will prompt for details to be entered and update the AWS CLI credential files with a profile that Terraform is able to use.

Terraform Session Token
Hit Enter on Role for Default

Role[TerraformRole]: myCustomRole
Code: 121314

Updating the profile [terraform_session] in the credentials file

There are some arguments you can use when running terraform-session-token, which can be viewed by parsing the '-h' or '--help' parameter. Be aware that disabling SSL Verification if you have a 'MITM Proxy' is not recommended, and will warn about its usage. It is better to use the CA Bundle instead, but this can be complicated.

usage: terraform-session-token.py [-h] [-d 3600] [-p terraform_session] [-v]

Generates a Session Token using a Role and MFA Device

optional arguments:
  -h, --help            show this help message and exit
  -d 3600               duration the token is valid (sec)
  -p terraform_session  profile name for the Session Token
  -v                    disables SSL Verification

Once you have authenticated you should have new profile listed within the AWS Crendentials file generally located under your home directory. This can then be called upon within Terraform's AWS Provider with 'profile'.

[terraform_session]
aws_access_key_id = AQIEIGHLPWAHLYFCDICA
aws_secret_access_key = VkFbHUsHvZ6HAT29w2seWdVzLUCQ/egg7A
aws_session_token = FQoDYXdzEOv\\\\\\\wEaDJZOEU69XfSIMDva3CLnASu3rGJvN8yW3oEbbhPwLiUb6AtqeILq3BmZR1Qr6bze8xlcwKdLZAoStT4drIlhuH7vQl1EaIDXT/AAeopW9siFupGnes+jTJXLMKmfslkngdlsndgVZWalDkRiH6Bg9ZgdkMXX34AV6Ro7MDpOwRVsRe+8/OSQPdtEPDBTfrSPTyALMSDFInieiownroiFJIlwEDsrBdd379ST3Gmftav4T4E9n4R1sxrVhtPqm0tvK7Y1lfgAJgftK+W4mwceygE27Q5xFnYaVxAHfd87dFSZvQLfRt5WIOEMZMZOjVDYCjGofXMBQ==

AWS Setup

Create a IAM Group with a policy to allow user accounts to assume the elevated access role. Anyone that you want to be able to switch into the Role is added to this group.

User Group Access Policy

Least Privileged Principles apply. The 'terraform_session' tool uses IAM to collect some details to make the AssumeRole Call to STS.

AWS (JSON) Example

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCollectionOfARNs",
      "Effect": "Allow",
      "Action": [
        "iam:ListMFADevices",
        "iam:GetRole",
        "iam:GetUser"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AllowGroupAssumeTerraformRole",
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::xxxxxxxxxxxx:role/TerraformRole"
    }
  ]
}

Terraform (HCL) Example

resource "aws_iam_policy" "assume_terraform" {
  name        = "AssumeTerraformRole"
  description = "Provides the ability to Assume the Terraform Role"
  policy      = "${data.aws_iam_policy_document.assume_terraform.json}"
}

data "aws_iam_policy_document" "assume_terraform" {
  statement {
    actions = [
      "iam:ListMFADevices",
      "iam:GetRole",
      "iam:GetUser",
    ]

    resources = ["*"]
  }

  statement {
    actions   = ["sts:AssumeRole"]
    resources = ["${aws_iam_role.terraform.arn}"]
  }

Terraform Role Trust Policy

The elevated access role has a trust policy that enforces the use of MFA, and who can attempt the action.

AWS (JSON) Example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAssumeRoleOnlyWithMFA",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

Terraform (HCL) Example:

resource "aws_iam_role" "terraform" {
  name               = "TerraformRole"
  description        = "High Privileged Access for Terraform"
  assume_role_policy = "${data.aws_iam_policy_document.terraform_trust.json}"
}

data "aws_iam_policy_document" "terraform_trust" {
  statement {
    principals {
      type = "AWS"

      identifiers = [
        "arn:aws:iam::xxxxxxxxxxxx:root",
      ]
    }

    actions = ["sts:AssumeRole"]

    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = ["true"]
    }
  }
}

Terraform

With a valid session_token profile Terraform Backend, Remote_State and the AWS Provider blocks can be setup to use the new profile. If you are using S3 for backend state files ensure the Role has access to the Bucket and DynamoDB Table for state lock.

Main.tf (HCL) Example:

terraform {
    required_version = ">= 0.10.2"

    backend "s3" {
        bucket         = "infrastructure-as-code"
        key            = "example/terraform.tfstate"
        region         = "us-east-1"
        encrypt        = "true"
        dynamodb_table = "terraform"
        profile        = "terraform_session"
    }
}

provider "aws" {
    region  = "us-east-1"
    profile = "terraform_session"
}

Variables.tf (HCL) Example:

data "terraform_remote_state" "example" {
  backend = "s3"

  config {
    bucket = "infrastructure-as-code"
    key    = "example/terraform.tfstate"
    region = "us-east-1"
    profile = "terraform_session"
  }
}

Authors

  • John Brandborg - Initial work - Linkedin

License

This project is licensed under the MIT License - see the LICENSE.md file for details