Help us understand the problem. What is going on with this article?

Terraformにおけるクロスアカウント構成なモジュール

More than 1 year has passed since last update.

これはDMM.com #2 Advent Calendar 2017 8日目の記事です。

カレンダーのURLはこちら
DMM.com #1 Advent Calendar 2017
DMM.com #2 Advent Calendar 2017

こんにちは@mafuyukです。
最近はAWSでクロスアカウントなログ収集基盤の設計、実装、構成の自動化をしていました。

本記事では実際に作成した、ログ収集基盤の構成を参考にTerraformにおけるクロスアカウント構成なモジュールについて紹介したいと思います。

ログ収集基盤の構成紹介

Untitled Diagram (3).png

構成図の説明

別々のAWSアカウントのログを一元管理したいという要件を満たすために用意したログ収集基盤の構成図です。

図の上部にあるAWSアカウントでは、ログの一元管理を行っていて、同じAWSアカウント内のログや複数の別AWSアカウントのログを1つのアカウントに集約しています。
AWSアカウント同士の連携はAssumeRoleで実現しています。

ログ収集の流れ

  1. CWLのログをサブスクリプションフィルターをトリガーとしたLambdaで取得
  2. LambdaはAssume Roleでアクセス権限を取得後、Kinesis FirehoseのAPIをcallしログをストリームに流し入れる
  3. ストリームはログ保管用S3とログ可視化用Elasticsearch Serviceに出力する

構成図の赤丸で囲った部分(上記の1と2の部分)をモジュール化します。

Terraform新機能

実践に入る前におめでたい話

祝Terraform v0.11 リリース

2017年11月16日にTerraform v0.11がリリースされましたー:tada::tada::tada::tada:

今回作成するモジュールのテンプレートではv0.11で新たに追加されたprovidersというオプションを利用するのでTerraformのversionを確認してください:bow:

対象version 0.11.1

v0.11で追加されたmoduleの新オプションprovidersとは??

v0.10まで

v0.10までmoduleを利用する際にはプロバイダの継承が暗黙的に行われていました

provider "aws" {
  version                 = "~> 1.0"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_module" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  // moduleを利用しているTerraform環境のデフォルトのプロパイダに対しての操作になる 
}

v0.11から

v0.11からはmoduleに対してプロバイダ情報をprovidersを使って明示的に渡す事ができるようになりました。

provider "aws" {
  version                 = "~> 1.0"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "foo"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_module" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  providers = {
    "aws" = "aws.foo" // module内のaws(デフォルト)の値がaws.fooプロパイダになる
    "aws.bar" = "aws" // module内のaw.barの値がデフォルトプロパイダになる
  }
}

:warning: module内で1つのプロバイダのみに対して操作する場合は、従来の暗黙的なプロバイダ継承を推奨すると公式に記載されていましたのでうまく使い分けましょう。

実践

module側プロパイダ設定

クロスアカウント構成を実現するためにmodule側でプロパイダ設定を2つ受け取れるようにします。

aws.tf
// ログがあるAWSアカウントのプロバイダ
provider "aws" {
  alias  = "src"
}

// ログを集約するAWSアカウントのプロバイダ
provider "aws" {
  alias  = "dst"
}

moduleを利用する

このモジュールを利用する場合は以下のようにprovidersを渡します。

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "myprov"
  profile                 = "myprov"
  region                  = "${var.myprov_region}"
  shared_credentials_file = "${var.shared_credentials_file}"
}

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "logprov"
  profile                 = "logprov"
  region                  = "${var.logprov_region}"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_resource" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  providers = {
    "aws.src" = "aws.myprov"
    "aws.dst" = "aws.logprov"
  }
}

受け取った2つのプロバイダ情報を利用する

参考にしたログの収集基盤では、AssumeRole周りで2つのプロパイダ構成を利用する必要がありました。
実際に今回の構成のどの部分に使ったのかみてみましょう。

iam.tf
resource "aws_iam_role" "lambda" {
  provider = "aws.src"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "writes_to_cwl_policy" {
  // ただのCWLへの書き込み権限なので省略
}

// src側のRoleにdst側のRoleに対してAssumeRoleを行えるポリシー付与
resource "aws_iam_role_policy" "fh_sts_policy" {
  provider = "aws.src"
  role     = "${aws_iam_role.lambda.id}"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "${aws_iam_role.lambda_assume.arn}"
    }
}
EOF
}

// dst側ではsrc側のロールがAssumeRoleを行った際に
// KinesisFirehoseの実行権限を持った一時クレデンシャルを発行することが可能なRoleを作成
resource "aws_iam_role" "lambda_assume" {
  provider = "aws.dst"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "${aws_iam_role.lambda.arn}"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "writes_to_fh_policy" {
  provider = "aws.dst"
  role     = "${aws_iam_role.lambda_assume.id}"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "firehose:PutRecordBatch",
      "Resource": [
        "${var.fh_stream_arn}" // 出力先のFirehoseのARN
      ]
    }
  ]
}
EOF
}

Terraformにおけるクロスアカウント構成なモジュールに必要な実装の紹介は以上です。
これで複数のAWSアカウントを股にかけたモジュールの作成ができるようになったと思います:100:

mfykmn
AWS、Terraform、Kubernetes、Docker、CircleCI、etc... ここらへんをよく触ります DevOpsを整える仕事が最近多く、これからSRE的な部分を学習していきます〜
http://mafuyuk.com/
bell-face
BtoBセールスに特化したインサイドセールスシステム、ベルフェイスを開発・運営しています
https://bell-face.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした