From d1d5e940cac16d2fffd92a8e9982a8c94944a58f Mon Sep 17 00:00:00 2001 From: Sean Rankine Date: Tue, 25 Jul 2023 18:15:17 +0100 Subject: [PATCH] Add AWS OIDC Provider for Terraform Cloud This adds a Terraform project for creating the AWS OIDC provider for use with Terraform Cloud. This also generates a variable set in Terraform Cloud that can be used by other workspaces to use the dynamic AWS credentials for permissions to Terraform AWS. This project uses workspaces manually created in Terraform Cloud (one workspace per AWS account). --- .../deployments/tfc-configuration/aws/main.tf | 114 ++++++++++++++++++ .../tfc-configuration/aws/provider.tf | 31 +++++ .../tfc-configuration/aws/variables.tf | 16 +++ 3 files changed, 161 insertions(+) create mode 100644 terraform/deployments/tfc-configuration/aws/main.tf create mode 100644 terraform/deployments/tfc-configuration/aws/provider.tf create mode 100644 terraform/deployments/tfc-configuration/aws/variables.tf diff --git a/terraform/deployments/tfc-configuration/aws/main.tf b/terraform/deployments/tfc-configuration/aws/main.tf new file mode 100644 index 000000000..d31e20d8b --- /dev/null +++ b/terraform/deployments/tfc-configuration/aws/main.tf @@ -0,0 +1,114 @@ +data "tls_certificate" "tfc_certificate" { + url = "https://${var.tfc_hostname}" +} + +resource "aws_iam_openid_connect_provider" "tfc_provider" { + url = data.tls_certificate.tfc_certificate.url + client_id_list = ["aws.workload.identity"] + thumbprint_list = [data.tls_certificate.tfc_certificate.certificates[0].sha1_fingerprint] +} + +resource "aws_iam_role" "tfc_role" { + name = "terraform-cloud" + + assume_role_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Federated" : "${aws_iam_openid_connect_provider.tfc_provider.arn}" + }, + "Action" : "sts:AssumeRoleWithWebIdentity", + "Condition" : { + "StringEquals" : { + "${var.tfc_hostname}:aud" : "${one(aws_iam_openid_connect_provider.tfc_provider.client_id_list)}" + }, + "StringLike" : { + "${var.tfc_hostname}:sub" : "organization:${var.tfc_organization_name}:project:*:workspace:*:run_phase:*" + } + } + } + ] + }) + + managed_policy_arns = [aws_iam_policy.tfc_policy.arn] +} + +resource "aws_iam_policy" "tfc_policy" { + name = "terraform-cloud-run" + description = "Permissions to allow Terraform Cloud to plan and apply" + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Resource" : "*", + "Action" : [ + "autoscaling:*", + "cloudfront:*", + "cloudwatch:*", + "ec2:*", + "ecr:*", + "eks:*", + "elasticache:*", + "elasticloadbalancing:*", + "es:*", + "events:*", + "iam:*", + "kms:*", + "logs:*", + "mq:*", + "rds:*", + "route53:*", + "s3:*", + "sns:*", + "sqs:*", + "wafv2:*" + ] + }, + { + "Effect" : "Deny", + "Resource" : "*", + "Action" : [ + "aws-marketplace:*", + "aws-marketplace-management:*", + "aws-portal:*", + "budgets:*", + "config:*", + "directconnect:*", + "ec2:*Purchase*", + "ec2:*ReservedInstances*", + "iam:*Login*", + "iam:*Group*", + "iam:*PermissionsBoundary*", + "iam:*Provider*", + "iam:*User*", + "iam:CreateServiceLinkedRole", + "iam:PassRole" + ] + } + ] + }) +} + +resource "tfe_variable_set" "variable_set" { + name = "aws-credentials-${var.aws_environment}" +} + +resource "tfe_variable" "tfc_var_aws_provider_auth" { + key = "TFC_AWS_PROVIDER_AUTH" + value = "true" + category = "env" + description = "Configures Terraform Cloud to authenticate with AWS using dynamic credentials" + variable_set_id = tfe_variable_set.variable_set.id +} + +resource "tfe_variable" "tfc_var_aws_run_role_name" { + key = "TFC_AWS_RUN_ROLE_ARN" + value = aws_iam_role.tfc_role.arn + category = "env" + description = "The ARN of the role to assume in AWS" + variable_set_id = tfe_variable_set.variable_set.id +} diff --git a/terraform/deployments/tfc-configuration/aws/provider.tf b/terraform/deployments/tfc-configuration/aws/provider.tf new file mode 100644 index 000000000..0b9794d19 --- /dev/null +++ b/terraform/deployments/tfc-configuration/aws/provider.tf @@ -0,0 +1,31 @@ +terraform { + cloud { + organization = "govuk" + workspaces { + tags = ["tfc", "aws", "configuration"] + } + } + + required_version = "~> 1.4" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.5" + } + + tfe = { + version = "~> 0.47.0" + } + } +} + +provider "aws" { + region = "eu-west-1" +} + +provider "tfe" { + hostname = var.tfc_hostname + organization = var.tfc_organization_name +} + diff --git a/terraform/deployments/tfc-configuration/aws/variables.tf b/terraform/deployments/tfc-configuration/aws/variables.tf new file mode 100644 index 000000000..b8c851c32 --- /dev/null +++ b/terraform/deployments/tfc-configuration/aws/variables.tf @@ -0,0 +1,16 @@ +variable "aws_environment" { + type = string + description = "The name of the AWS environment" +} + +variable "tfc_hostname" { + type = string + default = "app.terraform.io" + description = "The hostname of the TFC or TFE to use with AWS" +} + +variable "tfc_organization_name" { + type = string + default = "govuk" + description = "The name of the Terraform Cloud organization" +}