これはDMM.com #2 Advent Calendar 2017 8日目の記事です。
カレンダーのURLはこちら
DMM.com #1 Advent Calendar 2017
DMM.com #2 Advent Calendar 2017
こんにちは@mafuyukです。
最近はAWSでクロスアカウントなログ収集基盤の設計、実装、構成の自動化をしていました。
本記事では実際に作成した、ログ収集基盤の構成を参考にTerraformにおけるクロスアカウント構成なモジュールについて紹介したいと思います。
##構成図の説明
別々のAWSアカウントのログを一元管理したいという要件を満たすために用意したログ収集基盤の構成図です。
図の上部にあるAWSアカウントでは、ログの一元管理を行っていて、同じAWSアカウント内のログや複数の別AWSアカウントのログを1つのアカウントに集約しています。
AWSアカウント同士の連携はAssumeRoleで実現しています。
##ログ収集の流れ
- CWLのログをサブスクリプションフィルターをトリガーとしたLambdaで取得
- LambdaはAssume Roleでアクセス権限を取得後、Kinesis FirehoseのAPIをcallしログをストリームに流し入れる
- ストリームはログ保管用S3とログ可視化用Elasticsearch Serviceに出力する
構成図の赤丸で囲った部分(上記の1と2の部分)をモジュール化します。
Terraform新機能
実践に入る前におめでたい話
##祝Terraform v0.11 リリース
2017年11月16日にTerraform v0.11がリリースされましたー
今回作成するモジュールのテンプレートではv0.11で新たに追加されたproviders
というオプションを利用するのでTerraformのversionを確認してください
対象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の値がデフォルトプロパイダになる
}
}
module内で1つのプロバイダのみに対して操作する場合は、従来の暗黙的なプロバイダ継承を推奨すると公式に記載されていましたのでうまく使い分けましょう。
#実践
##module側プロパイダ設定
クロスアカウント構成を実現するためにmodule側でプロパイダ設定を2つ受け取れるようにします。
// ログがある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つのプロパイダ構成を利用する必要がありました。
実際に今回の構成のどの部分に使ったのかみてみましょう。
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アカウントを股にかけたモジュールの作成ができるようになったと思います