giftee Tech Blog

ギフティの開発を支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信しています。

AWSアカウント管理をコード化する

増えるプロダクトとAWSアカウント

こんにちは。R&Dの一環と称しマリオカート ライブ ホームサーキットを業務終了後にオフィスで遊んでいるギフティCTOの柳瀬です。 管轄するCTO室ではこういった(?)R&Dだけでは無く、全社横断でインフラ面の管理なども行っています。

といってもギフティのエンジニアリング組織は「自己組織的」であることを大事にしているので、CTO室側でやっているインフラ業務はかなり限定的です。また基本的にインフラは全てAWS上で動いており、AWSの提唱するベストプラクティスも参照しつつ、各チームが自律的に動けるように、プロダクト単位でAWSアカウントを作成する形式を選択しています。

そのため、「AWSアカウントの作成」というのは割とカジュアルに発生する業務です。昔は人の作業でアカウントを作成する温かみのある運用だったのですが、作業の属人性や漏れなどの課題があり、現在ではterraformを用いた管理になっています。今回の記事では弊社の今の管理方法を共有できればと思います。

Organizationの構成

その前段として、AWSアカウント群の構成をご紹介します。現在はシンプルに一つのMaster(Payer)アカウントに他の全てのアカウントがぶら下がる構成になっています。アカウントは基本的には2種類で、プロダクトを動かすためのアカウントと、エンジニア個々人が一定金額枠の中で自由に使えるSandboxアカウントになります。

ちなみに、プロダクトの検証環境と本番環境でAWSアカウントを分ける構成も一度試したのですが、現在の弊社の平均的なプロダクトのサイズだとアカウントが異なることによるオーバヘッドの方が大きいという判断になりました。そのため、今は検証環境と本番環境はAWSアカウントとしては同一になっています。

管理方法

terraformのaws_organizations_accountを使ってAWSアカウントをリソースとして管理しています。下記はそのmain.tfの記述の抜粋となります。

resource "aws_organizations_account" "this" {
  name  = var.account_name
  email = var.account_email
  role_name = "OrganizationAccountAccessRole"

  iam_user_access_to_billing = var.iam_user_access_to_billing

  lifecycle {
    ignore_changes = [role_name]
  }

  tags = {
    service = var.service_tag
    profile_name = var.profile_name_tag
  }
}

例えばIAMによる請求情報のアクセス許可など、どのアカウントでも設定しておきたい内容をここに取りまとめて置くことで確実にその設定がなされることを実現しています。

他にも、「個人用Sandboxには指定額の予算設定をする」といった共通的に求められる設定をterraformのmodulesで定義することにより実現しています。下記はその記述の一部です。

resource "aws_budgets_budget" "this_budget" {
  name = "${var.account_name}-${aws_organizations_account.this.id}-monthly"
  budget_type = "COST"
  limit_amount = var.billing_alarm_usd_per_month
  limit_unit = "USD"

  time_unit = "MONTHLY"
  time_period_start = "2020-02-07_00:00"

  cost_filters = {
    LinkedAccount = aws_organizations_account.this.id
  }

  # https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budget-costtypes.html
  # https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/awsaccountbilling-aboutv2.pdf
  cost_types {
    include_tax                = true # 予算に税金を含めるかどうかを
    include_subscription       = true # 予算にサブスクリプションを含めるかどうか
    include_refund             = true # 予算に返金を含めるかどうか
    include_credit             = true # 予算にクレジットを含めるかどうか
    include_upfront            = true # 予算に前払い RI コストを含めるかどうか
    include_recurring          = true # 予算に月額 RI コストなどの定期的な手数料を含めるかどうか
    include_other_subscription = true # 予算に非 RI サブスクリプションコストを含めるかどうか
    include_support            = true # 予算にサポートサブスクリプション料金を含めるかどうか
    include_discount           = true # 予算に割引を含めるかどうか
    use_blended                = false # 予算にブレンドレートを使用するかどうか
    use_amortized              = false # 予算で償却率を使用するかどうか
  }

  # e-mail notification
  notification {
    notification_type          = "ACTUAL"

    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    comparison_operator        = "GREATER_THAN"

    subscriber_email_addresses = [var.billing_alarm_subscriber_email_address]
  }

ちなみにここでは、予算超過時にメール通知を行う部分までを自動的に指定、それによりメール経由でSlackにも連絡が行くようになっています。これをCTO室メンバーが拾い、下記のように個別にリマインドを掛ける運用になっています。

まとめ

terraform公式ドキュメントにある通り、実はアカウント削除時が手間、みたいな問題もあるのですが、現状この仕組みによりAWSアカウントの運用の属人化低下と安定性向上が図れたと考えています。

また現在弊社ではCTO室で「コスト」と「セキュリティ」を中央集権的に管理し、その他は各事業部のエンジニアに委ねる責任分解を図っています。その取組を進める上で横断的な対応をAWSアカウントに対して実施する際に、こうした管理機構が大いに助けになると考えています。