継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

AWS Cost Usage Report を定期的に Storage Transfer Service で Google Cloud Service に転送するのを Terraform で設定する

タダです.

以前の記事で AWS Cost Usage Report (以下,Cost Usage Report )を BigQuery にロードして Locker Studio で可視化したのですが,この記事では手動オペレーションになっていた AWS -> GCS へのデータを連携する部分の仕組み化と Terrafrom としてコード化したのをまとめていきます.

sadayoshi-tada.hatenablog.com

仕組み化の概要

Cost Usage Report が毎日 AM 9時頃に S3 に出力することができるため,左記時間以降で Storage Transfer Service(以下,STS) で Google Storage Service(以下,GCS)に転送するジョブを設定することにしました.この記事では STS で GCS に Cost Usage Report を送る部分の処理を Terraform 化したのでそこにフォーカスします.

仕組み化部分のTerraform のコード

GCP -> AWS の認証

STS の転送で S3 バケットへのアクセスするために OIDC を使います.サービスアカウントのクライアント ID は googleServiceAccounts.get メソッドでプロジェクト ID を入れて取得します.

data "aws_iam_policy_document" "sts_cost_usage_report_trust_policy" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      type        = "Federated"
      identifiers = ["accounts.google.com"]
    }
    condition {
      test     = "StringEquals"
      variable = "accounts.google.com:sub"
      values   = ["サービスアカウントのクライアントID"]
    }
  }
}
resource "aws_iam_role" "sts_cost_usage_report_role" {
  name               = "hoge"
  assume_role_policy = data.aws_iam_policy_document.sts_cost_usage_report_trust_policy.json
}
data "aws_iam_policy_document" "sts_cost_usage_report_policy" {
  statement {
    effect = "Allow"
    actions = [
      "s3:GetObject",
    ]
    resources = ["arn:aws:s3:::${バケット名}/*"]
  }
  statement {
    effect    = "Allow"
    actions   = ["s3:ListBucket"]
    resources = [arn:aws:s3:::${バケット名}}"]
  }
}
resource "aws_iam_role_policy" "sts_cost_usage_report_policy" {
  name   = "hoge"
  role   = aws_iam_role.sts_cost_usage_report_role.name
  policy = data.aws_iam_role_policy.sts_cost_usage_report_policy.json
}

関連情報

cloud.google.com

STS の転送設定

STS の転送設定を行うにあたって GCS,STS のサービスアカウントに権限付与,定期実行用ジョブを用意します.転送ジョブは毎朝 AM 10時に実行するようにしています.

resource "google_storage_bucket" "cost_usage_report_bucket" {
  project       = "プロジェクトID"
  name          = "hoge"
  location      = "asia-northeast1"
  force_destroy = false
  storage_class = "STANDARD"
  encryption {
    default_kms_key_name = [KMS キー ID]
  }
  public_access_prevention    = "enforced"
  uniform_bucket_level_access = true
}
resource "google_storage_bucket_iam_member" "sts_write_cost_usage_report_bucket" {
  bucket = google_storage_bucket.cost_usage_report.name
  role   = "roles/storage.legacyBucketWriter"
  member = "serviceAccount:project-[プロジェクトID]@storage-transfer-service.iam.gserviceaccount.com"
}
resource "google_storage_transfer_job" "cost_usage_report_transfer_job" {
  description = "AWS Cost Usage Report Transfer Job"
  project     = [プロジェクトID]
  transfer_spec {
    aws_s3_data_source {
      bucket_name = [転送元バケット名]
      role_arn    = [GCP -> AWS の認証で作った IAM ロール ARN]
      path        = [転送するデータが有るパス]
    }
    gcs_data_sink {
      bucket_name = google_storage_bucket.cost_usage_report_bucket.name
      path        = [転送先パス]
    }
  }
  schedule {
    schedule_start_date {
      year  = 2023
      month = 開始月
      day   = 開始日
    }
    start_time_of_day {
      hours   = 1
      minutes = 0
      seconds = 0
      nanos   = 0
    }
  }
}

関連情報

registry.terraform.io

以上で Cost Usage Report を STS で GCS に転送する部分のコードができます.自分が遭遇した躓きとしては,IAM ロールの設定に誤りがあったりすると,転送ジョブが作られず Failed to obtain the location of the source S3 bucket. Additional details: Access Denied といったメッセージが出てしまっていました.他のエラーは下記のドキュメントを参照ください.

cloud.google.com

まとめ

Cost Usage Report を STS で GCS に転送するのを Terraform 化しました.これで GCP 側にデータを持ってこれたのであとは BigQuery に対してクエリかけて可視化するだけだって感じなのですが,会社の記事にも書きましたが dbt も用いていたのでその辺の学びを記事にしていければと思います.