👥

【terraform】yamlファイルにちょっと書くだけでリソース作成できる仕組みを作りたい

に公開

概要

terraformを知らなくても、簡単な項目だけ書けばリソースをデプロイできる仕組みをterraformで用意しました
こんな感じのイメージです

  • 開発者: yamlファイルに必要項目を書く
  • SRE(インフラ): ↑を反映させるTFを用意する

題材

題材はECRリポジトリにします
ユーザは以下の情報だけを記述すればよいものとします

  • リポジトリ名
  • チーム名(tagに反映する)
  • mutable or immutable
  • IAMロール(リポジトリポリシーに反映する)

ユーザに書いてもらうファイル

yamlにしました

- name: frontend-app
  team: team-alpha
  immutable: false
  iam_roles:
    - arn:aws:iam::123456789012:role/team-alpha-deploy-role
    - arn:aws:iam::123456789012:role/ci-cd-role

- name: backend-api
  team: team-alpha
  immutable: true
  iam_roles:
    - arn:aws:iam::123456789012:role/team-alpha-deploy-role

- name: batch-worker
  team: team-beta
  immutable: false
  iam_roles:
    - arn:aws:iam::123456789012:role/team-beta-deploy-role

TFコード

# YAMLファイルを読み込み
locals {
  repositories = yamldecode(file("${path.module}/ecr-repositories.yaml"))

  # リポジトリ名をキーとしたマップに変換
  repositories_map = {
    for repo in local.repositories : repo.name => repo
  }
}

# ECRリポジトリの作成
resource "aws_ecr_repository" "this" {
  for_each = local.repositories_map

  name                 = each.value.name
  image_tag_mutability = each.value.immutable ? "IMMUTABLE" : "MUTABLE"

  tags = {
    Name      = each.value.name
    Team      = each.value.team
    ManagedBy = "terraform"
  }
}

# リポジトリポリシーの設定
resource "aws_ecr_repository_policy" "this" {
  for_each = local.repositories_map

  repository = aws_ecr_repository.this[each.key].name

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AllowPushPull"
        Effect = "Allow"
        Principal = {
          AWS = each.value.iam_roles
        }
        Action = [
          "ecr:GetDownloadUrlForLayer",
          "ecr:BatchGetImage",
          "ecr:BatchCheckLayerAvailability",
          "ecr:PutImage",
          "ecr:InitiateLayerUpload",
          "ecr:UploadLayerPart",
          "ecr:CompleteLayerUpload"
        ]
      }
    ]
  })
}

# ライフサイクルポリシー(オプション)
resource "aws_ecr_lifecycle_policy" "this" {
  for_each = local.repositories_map

  repository = aws_ecr_repository.this[each.key].name

  policy = jsonencode({
    rules = [
      {
        rulePriority = 1
        description  = "Keep last 10 images"
        selection = {
          tagStatus   = "any"
          countType   = "imageCountMoreThan"
          countNumber = 10
        }
        action = {
          type = "expire"
        }
      }
    ]
  })
}

ポイントはYAMLファイルからリポジトリ設定を読み込むところです
ecr-repositories.yamlファイルを読み込みリスト形式のデータを取得、リストをマップ(辞書)形式に変換し、リポジトリ名をキーとして使用しています
あとはfor_eachで処理するだけです

動作確認

これをapplyすると

$ terraform state list
aws_ecr_lifecycle_policy.this["backend-api"]
aws_ecr_lifecycle_policy.this["batch-worker"]
aws_ecr_lifecycle_policy.this["frontend-app"]
aws_ecr_repository.this["backend-api"]
aws_ecr_repository.this["batch-worker"]
aws_ecr_repository.this["frontend-app"]
aws_ecr_repository_policy.this["backend-api"]
aws_ecr_repository_policy.this["batch-worker"]
aws_ecr_repository_policy.this["frontend-app"]

よさそうです
yaml1つ用意しておけば、すぐにチーム専用のリソースを作成できます

まとめ

意外と簡単にterraformファイルはできたので、チーム毎に必要なAWSリソースがあったら使ってみると便利かと思います
モジュールにも応用できる手法です

ただ書いていて、「immutableってわかりずらい?」「なんのためにIAMロール設定するの?」等の疑問は生じると思うので、ちゃんとREADMEに説明書くなりするのが大事と思いました

Discussion