🙄

Terraform Cloudを使ったシークレットキー不要のAWSリソース管理

2024/08/25に公開

はじめに

AWS を中心にクラウド関連のキャッチアップを行なっていますが、悪戦苦闘している今日この頃です。
今回、 Terraform で AWS リソースを作成して遊んでいる際に、ふとチーム開発の時に tfstate の管理をどうやるのが良いかという疑問が生まれ、調べている中で Terraform Cloud に出会いました。

https://dev.classmethod.jp/articles/terraform_tfstate_management_tfc/

Terraform Cloud を使用することで、IAMユーザーやシークレットキーを発行することなく、OIDC(OpenID Connect)の仕組みを利用してAWSリソースの管理ができることを知り、体験として良かったので、今回はその方法について紹介します。

https://aws.amazon.com/blogs/apn/simplify-and-secure-terraform-workflows-on-aws-with-dynamic-provider-credentials/


AWS 公式ブログ

前準備

まず、Terraform Cloud のアカウントがない方は、以下のリンクからアカウントを作成してください。

https://app.terraform.io/session

Terraform Cloud 上にワークスペースを作成

Terraform Cloud にログイン後、任意の Organization を作成し、その中にワークスペースを作成します。今回は CLI を使用して動作確認を行うため、「CLI-Driven Workflow」でワークスペースを作成してください。


OIDC のためのAWSリソースを作成

まず、任意のディレクトリを作成し、その中に trust ディレクトリを作成します。次に、以下のファイルを作成します。

└── trust
    ├── main.tf
    ├── outputs.tf
    ├── terraform.tfvars
    └── variables.tf

以下にmain.tfの内容を示します。

main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.56.1"
    }
  }
}

provider "aws" {
  default_tags {
    tags = {
      Terraform = "true"
    }
  }
}

# TLS 証明書を取得するためのデータソースを定義
data "tls_certificate" "terraform_cloud" {
  url = "https://${var.terraform_cloud_host}"
}

# Terraform Cloud 用の OpenID Connect プロバイダを定義
resource "aws_iam_openid_connect_provider" "terraform_cloud" {
  url = data.tls_certificate.terraform_cloud.url
  # OpenID Connect audience
  client_id_list  = ["aws.workload.identity"]
  thumbprint_list = [data.tls_certificate.terraform_cloud.certificates[0].sha1_fingerprint]
}

# 信頼ポリシー
data "aws_iam_policy_document" "terraform_assume_role_policy" {
  statement {
    effect = "Allow"

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.terraform_cloud.arn]
    }

    actions = ["sts:AssumeRoleWithWebIdentity"]

    condition {
      test     = "StringEquals"
      variable = "${var.terraform_cloud_host}:aud"

      values = [
        # OpenID Connect audience
        one(aws_iam_openid_connect_provider.terraform_cloud.client_id_list)
      ]
    }

    condition {
      test     = "StringLike"
      variable = "${var.terraform_cloud_host}:sub"

      values = [
        "organization:${var.terraform_cloud_organization}:project:*:workspace:*:run_phase:*"
      ]
    }
  }
}

resource "aws_iam_role" "terraform_role" {
  name               = "terraform-role"
  assume_role_policy = data.aws_iam_policy_document.terraform_assume_role_policy.json
}

# Terraform Cloud を介して AWS リソースを管理するためのポリシーになります。
# 用途によっては、より制限の厳しいポリシーを適用してください
data "aws_iam_policy_document" "terraform_policy" {
  statement {
    effect    = "Allow"
    actions   = ["*"]
    resources = ["*"]
  }
}

resource "aws_iam_policy" "terraform_policy" {
  name        = "terraform-policy"
  description = "Policy for Terraform Cloud"
  policy      = data.aws_iam_policy_document.terraform_policy.json
}

resource "aws_iam_role_policy_attachment" "terraform_policy_attachment" {
  role       = aws_iam_role.terraform_role.name
  policy_arn = aws_iam_policy.terraform_policy.arn
}

variables.tf は以下のように定義します。

variables.tf
variable "terraform_cloud_host" {
  type        = string
  description = "Terraform Cloud のホスト名"
}

variable "terraform_cloud_organization" {
  type        = string
  description = "Terraform Cloud の組織名"
}

次に、terraform.tfvars を以下のように定義します。

terraform.tfvars
terraform_cloud_host         = "app.terraform.io"
terraform_cloud_organization = "作成した Organization の名前"

最後に、Terraform Cloud の設定で必要な IAM ロールの ARN を出力するために、outputs.tfを以下のように定義します。

outputs.tf
output "role_arn" {
  description = "Terraform 実行用のロール ARN"
  value       = aws_iam_role.terraform_role.arn
}

これで準備が整いました。terraform applyを実行し、出力された IAM ロールの ARN を控えておいてください。

Terraform Cloud に環境変数を設定する

Terraform Cloud のダッシュボードで作成したワークスペースの詳細ページに進み、左側のサイドメニューから「Variables」を選択します。そして、以下の2つの環境変数を設定します。

環境変数名
TFC_AWS_PROVIDER_AUTH true
TFC_AWS_RUN_ROLE_ARN 手元に控えておいた IAM ロールの ARN

これで OIDC 認証を行うための準備は全て完了となります!

Terraform Cloud の介して AWS リソースを作成する

ターミナルで terraform login を実行し、表示される指示に従ってログインを行います。

https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-login

次に、trust ディレクトリと同階層に infra ディレクトリを作成し、main.tf ファイルを新たに作成します。

├── infra
│   └── main.tf
└── trust

main.tf は以下のように定義します。

main.tf
terraform {
  cloud {
    organization = "作成した Organization の名前"

    workspaces {
      name = "作成したワークスペースの名前"
    }
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.56.1"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

最後に、terraform apply を実行して AWS リソースが作成できることを確認します。今回は、VPC を 1 つ作成します。

main.tf
terraform {
  cloud {
    organization = "作成した Organization の名前"

    workspaces {
      name = "作成したワークスペースの名前"
    }
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.56.1"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

+ resource "aws_vpc" "main" {
+   cidr_block           = "10.0.0.0/16"
+   enable_dns_support   = true
+   enable_dns_hostnames = true
+ }

terraform apply を実行し、期待通りにVPCが作成できました🎉

最後に

Terraform Cloud を活用することで、従来の IAM ユーザーやシークレットキーを使用せずに、セキュアかつ効率的に AWS リソースを管理する方法を紹介しました。また、Terraform Cloud の Free プランでは、1 organization あたりメンバー数に制限なく500リソースまで作成可能であるため、チーム開発においても積極的に導入していく価値があるなと感じました。

しくみのテックブログ

Discussion