TerraformによるAWSマルチアカウント管理 in eureka, Inc.

TerraformによるAWSマルチアカウント管理 in eureka, Inc.

X-Tech JAWS & JAWS-UGアーキテクチャ専門支部 コラボ勉強会#02
https://jawsug-arch.connpass.com/event/135191/

Bee9ae4bc9ccb3ca6b01818eb7ad0856?s=128

Daichi Harada

July 30, 2019
Tweet

Transcript

  1. Terraformによる AWSマルチアカウント管理 in eureka, Inc. Daichi Harada / 2019.07.30
 X-Tech

    JAWS & JAWS-UGアーキテクチャ専門支部 
 コラボ勉強会#02

  2. アジェンダ - 自己紹介 / eureka について - eureka における Infrastructure

    as Code - 最近の悩み - AWS マルチアカウント化を進めている話 - terraform でマルチアカウント管理をうまくやる方法 - terraform module のつかいどころ - terraform の multi provider のつかいどころ
  3. DAICHI HARADA - @kai_ten_sushi / @dharada1 - SRE at eureka,

    Inc. - 2018 年新卒入社 - 好き - terraform / AWS / datadog / go - 勉強中 - kubernetes / fastly
  4. eureka, Inc. - 事業 - Pairs ( 日本 / 台湾

    / 韓国 ) - Couples - Pairs エンゲージ ← ❗❗
  5. Eureka Engineering Team - エンジニア - 50 名 - SRE

    - 5 名 - すべてのサービスのインフラを管 轄 - オウンドメディア / コーポレートサイ トなど含む - Data Pipeline - Security - Audit
  6. Eureka Engineering Team - 開発チームも最近 AWS を使い始めている - Rekognition のサービス導入

    (API Developer) - CloudFront + Lambda@Edge による画像変換 & 配信シ ステム - マネージド機械学習サービスの検証 AWS AI Service Seminarに登壇しました! https://medium.com/eureka-engineering/aws-ai-se rvice-seminar-87a6de178886 CloudFront + Lambda@Edge
  7. Infastructure as Code tools in Eureka - Provisioning - Terraform

    - Pairs / Pairs Engage はすべてがコード管理下に - Ansible + Packer - golden image (ami) + immutable infrastructure model - Serverless - Serverless Framework - 画像変換機構の一部で Pairs での利用実績あり ( Cloudfront + Lambda@Edge ) - Container - ECS - Pairs 日台韓 - Kubernetes - 投稿審査マイクロサービス
  8. 最近

  9. 新サービスのリリース 新サービス リリース するぞォ! ・異なるサービスは分離して管理したい。 ・リリースまで、スピード重視で小回りを効かせていきたい。 ・既存のコンポーネントに影響出し得ない形でやっていきたい 新サービス リリース するぞォ!

    新サービス リリース するぞォ!
  10. 監査/セキュリティ/会計 wordpressの セキュリティ大 丈夫 ? 監査・セキュリティ対応 コストは、どこの部署 / サービスでどのぐらい使ってるのか把握したい。 監査で〜す

    WebOps費用 どんぐらい 使ってんの〜
  11. エンジニアからの要求 Rekognition 検証したい んだけど〜 ISUCONの 練習環境 立ててよ! Slack Bot 作ったから

    デプロイよろ♪ ホビー・プロジェクト、野良プロジェクト、検証環境のニーズが増してきた。 → 最低限のセキュリティ要件は守りつつ、開発者へのセルフサービス化を行いたい。   また、それらが本番環境や本気サービスに影響しないようにしたい。
  12. 新サービス リリース するぞォ! 監査で〜す wordpressの セキュリティ大 丈夫 ? WebOps費用 どんぐらい

    使ってんの〜 ISUCONの 練習環境 立ててよ! Slack Bot 作ったから デプロイよろ♪ Rekognition 検証したい んだけど〜
  13. 勢いがある❗

  14. Multi Account in AWS (AWS Organization)

  15. Multi Account in AWS (AWS Organization) https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_getting-started_concepts.html AWS Organization

  16. マルチアカウントで実現したいこと - Security / Audit / Financial Report - 締めるところ、当然やる

    - 請求情報 / 監査用ログ の集約 - 権限管理 - 影響範囲の分離 - マルチアカウントはリソース境界を分ける強力な手段 - サービス毎に分離 - ステージ毎に分離 - セキュリティレベルで分離 - 権限委譲 ( 開発スピードの担保 ) - 開発者は自由に使える検証環境がほしい - コントローラブルな状態を保ちつつ、ほどよく権限移譲していく
  17. 全体像 ︙ prod-xxxxx stage-xxxxx sandbox @eure.jpのアカウント IDaaS グループ管理 各アカウント共通のコンポーネント (あとで説明します)

    - IAM Role + Okta Integration - Datadog Integration - EC2 Auto-Patcher (Inspector+Lambda) - AWS Event Notify (Lambda) - etc. Master Account ( 請求情報 ) すべてのAWSアカウントを監視 Master Accountでは CloudTrailログの集約や 請求情報を統一して管理 (Consolidated Billing) している
  18. アカウントの切り方 - Master Account - eureka-paid ( 命名は Consolidated Billing

    のなごり ) - サービス単位での分割 - pairs / couples / corporate ... - prod/stage - prod-xxxxx / stage-xxxxx - sandbox - eureka-sandbox - ml-sandbox
  19. マルチアカウントで こまった事

  20. 管理が面倒... - IAM ユーザーの管理が行き届かない - コンソールのログインやり直しがいちいち面倒 - アカウントごとに監視できてたり出来てなかったりする - 新規アカウント発行の腰が重い

  21. 共通で利用したいリソースが多い - IAM Role 設計 - infra_developer / api_developer /

    read_only … - 外部サービスインテグレーション - Okta (IDaaS) を導入して各アカウントへの SAML を実現する - Datadog ( 監視 ) - VPC Peering - ssh 用 bastion サーバの VPC と peering が必要 - Lambda - aws-event-notify - インスタンスの退役予告を Slack 通知してくれる - Auto-Patcher - (Inspector + SNS + Lambda + SSM)
  22. 作成/変更の手間 - 新規作成 - 素朴に全部コピペして terraform apply するのは大変すぎる ... -

    変更 - 運用ツール・仕組みの標準化 - 差分を許容したくなかった
  23. terraform moduleで解決

  24. 共通の初期要件をmodule化 - アカウント毎に module を呼び出す と、初期要件のリソースが全部立 ち上がるようにした - VPC 設計、サービス名、

    env (prod/stage) などの変数を入れて呼 び出す - 実体のリソース数は多めだが呼び出 し側では隠蔽 - terraform apply するだけ、手作業なし https://www.terraform.io/docs/configuration/modules.html
  25. aws_account_bootstrap moduleの使い方 - アカウントごとに module を呼び出 すだけ。 module "aws_account_bootstrap" {

    // module呼び出し source = "../../global_modules/aws_account_bootstrap" // 新規作成した AWSアカウントの IDを渡す aws_caller_identity = "${data.aws_caller_identity.current.account_id}" // CIDR設計を外から指定 vpc_cidr = "10.11.0.0/16" zone_1a = "ap-northeast-1b" zone_1c = "ap-northeast-1c" subnet_public_1a = "10.11.10.0/24" subnet_public_1c = "10.11.11.0/24" subnet_private_1a = "10.11.20.0/24" subnet_private_1c = "10.11.21.0/24" // VPC Peering 用 (既存のbastion側のVPC IDを渡す) peering_vpc_id = "vpc-xxxxxx" peering_vpc_public_route_table_id = "rtb-xxxxxx" peering_vpc_private1a_route_table_id = "rtb-xxxxxx" peering_vpc_private1c_route_table_id = "rtb-xxxxxx" // AWSのリソースに振るタグ tag_name = "eureka" tag_env = "prod" // Datadogのメトリクスに付くタグ datadog_aws_integration_host_tag = "account:eureka" } // Provider // 新規発行したアカウントのキーを指定 (ファイルごとに分けているが profileでも可) provider "aws" { region = "${var.vpc["region"]}" shared_credentials_file = "/path/to/my/credentials" version = "= 1.52.0" } // Providerに食わせた AWSアカウントの情報を取得できる。 data "aws_caller_identity" "current" {}
  26. 共通のリソースは moduleで再利用する

  27. AWS + Okta Integration - SSO ツールの Okta を利用 -

    ワンクリックで各アカウントへ - IAM Role へのフェデレーションアクセス - ユーザーと権限の紐付けは Okta 側での管理
  28. AWS + Okta Integration - bootstrap のテンプレートには Okta とのインテ グレーション用のリソースを定義

    - aws_iam_user - aws_iam_policy - aws_iam_user_policy_attachment resource "aws_iam_user" "okta" { name = "okta" path = "/" } resource "aws_iam_policy" "okta" { name = "OktaMasterAccountPolicy" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:ListRoles", "iam:ListAccountAliases" ], "Resource": "*" } ] } EOF } resource "aws_iam_user_policy_attachment" "okta" { depends_on = [ "aws_iam_user.okta", "aws_iam_policy.okta", ] user = "${aws_iam_user.okta.name}" policy_arn = "${aws_iam_policy.okta.arn}" }
  29. IAM Role - Role 設計は全 AWS アカウントで共通 - admin -

    infra_developer - SRE が日常的に利用する - api_developer - dynamo / sqs / s3 など一部頻繁に発生する ものの create 権限 - ml_developer - ML 系マネージドサービス - bi_developer - athena とか - read_only - read only. - IAM User はなるべく作成しない - キーの管理など面倒なので
  30. サービスをまたぐ インテグレーションを terraformで表現

  31. AWS + Datadog Integration - AWS 側に IAM Role を作成

    - Datadog 側で吐き出した AWS External ID の指定 - 「 Datadog の」 AWS アカウントに操作を許可する - Datadog 側でアカウント ID と IAM Role 名、監視対象の設定
  32. AWS + Datadog Integration - 複数アカウント運用する場合正 直手作業はしんどい - マルチプロバイダーを使えば terraform

    apply 1 回でインテグ レーション可能
  33. 例1. Fastly + BigQuery - コード例を乗せる // Datadogが利用するIAM Role resource

    "aws_iam_role" "datadog_aws_integration" { depends_on = [ "datadog_integration_aws.aws", ] name = "DatadogAWSIntegrationRole" description = "Role for Datadog AWS Integration" assume_role_policy = "${data.aws_iam_policy_document.datadog_aws_integration_assume_role.json}" } // IAMポリシー data "aws_iam_policy_document" "datadog_aws_integration_assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "AWS" identifiers = ["arn:aws:iam::464622532012:root"] // DatadogのAWSアカウント } condition { test = "StringEquals" variable = "sts:ExternalId" values = [ "${datadog_integration_aws.aws.external_id}", ] } } } // Datadog側のIntegrationを定義 resource "datadog_integration_aws" "aws" { provider = "datadog.datadog" account_id = "${data.aws_caller_identity.current.account_id}" role_name = "DatadogAWSIntegrationRole" // AWS側で作成する IAM Role名 host_tags = [ "${var.datadog_aws_integration_host_tag}", ] } // moduleを呼ぶ側 … マルチプロバイダー指定 provider "aws" { region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" } provider "datadog" { alias = "datadog" version = "=1.9.0" } // Providerに食わせた AWSアカウントの情報を取得できる。 data "aws_caller_identity" "current" {}
  34. 例1. Fastly + BigQuery - コード例を乗せる // Datadog側のIntegrationを定義 resource "datadog_integration_aws"

    "aws" { provider = "datadog.datadog" account_id = "${data.aws_caller_identity.current.account_id}" role_name = "DatadogAWSIntegrationRole" // AWS側で作成する IAM Role名 host_tags = [ "${var.datadog_aws_integration_host_tag}", ] } // moduleを呼ぶ側 … マルチプロバイダー指定 provider "aws" { region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" } provider "datadog" { alias = "datadog" version = "=1.9.0" } // Providerに食わせた AWSアカウントの情報を取得できる。 data "aws_caller_identity" "current" {} - aws のアカウント ID を provider のク レデンシャルから取得 - Datadog 側の Integration 用リソー スに与えることでインテグレーショ ンが可能
  35. AWSアカウントをまたぐ VPC Peering

  36. Cross-Account VPC Peering - Bastion サーバからの ssh を開通したい。 - VPC

    Peering してあげないと ssh できない - 複数のアカウントをまたぐ Peering ってどうやる の? - Peering リクエスト、アクセプターという概念 - 毎回手作業はしんどい - これもマルチプロバイダーを使うと 1 apply で 開通可能。 - alias をはって、複数アカウントのリソースを一気 に作れる。
  37. 例1. Fastly + BigQuery - コンソールでのアクセプト作業を terraform で表現可能 - provider

    の alias を明示的に指定して利用 - 異なる provider のリソースも普通に呼び合うことができる - 例 … aws_vpc_peering_connection.peering.id // generalのアカウントから、新しい awsアカウントへの peering resource "aws_vpc_peering_connection" "peering" { provider = "aws.general" vpc_id = "${data.aws_vpc.peering_vpc.id}" peer_owner_id = "${data.aws_caller_identity.current.account_id}" peer_vpc_id = "${aws_vpc.vpc.id}" auto_accept = "false" } // 新規awsアカウントから、アクセプトする。 resource "aws_vpc_peering_connection_accepter" "general_to_new_vpc" { vpc_peering_connection_id = "${aws_vpc_peering_connection.peering.id}" auto_accept = "true" tags = { Side = "Accepter" } } // 1つめのaws provider // (新しく作るアカウントの方 ) provider "aws" { region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" } // エイリアスをはると //2つめのaws providerを使える // (bastionサーバが置いてあるアカウント ) provider "aws" { alias = "general" region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" }
  38. 例1. Fastly + BigQuery - コンソールでのアクセプト作業を terraform で表現可能 - provider

    の alias を明示的に指定して利用 - 異なる provider のリソースも普通に呼び合うことができる - 例 … aws_vpc_peering_connection.peering.id // generalのアカウントから、新しい awsアカウントへの peering resource "aws_vpc_peering_connection" "peering" { provider = "aws.general" vpc_id = "${data.aws_vpc.peering_vpc.id}" peer_owner_id = "${data.aws_caller_identity.current.account_id}" peer_vpc_id = "${aws_vpc.vpc.id}" auto_accept = "false" } // 新規awsアカウントから、アクセプトする。 resource "aws_vpc_peering_connection_accepter" "general_to_new_vpc" { vpc_peering_connection_id = "${aws_vpc_peering_connection.peering.id}" auto_accept = "true" tags = { Side = "Accepter" } } // 1つめのaws provider // (新しく作るアカウントの方 ) provider "aws" { region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" } // エイリアスをはると //2つめのaws providerを使える // (bastionサーバが置いてあるアカウント ) provider "aws" { alias = "general" region = "${var.region}" shared_credentials_file = "/path/to/credfile" version = "= 2.11.0" }
  39. まとめ

  40. まとめ - eureka では 複数の AWS アカウント を terraform で運用している

    - terraform module でテンプレを作ると、共通リソース管理が楽になる - IAM 設計、運用ツール系の lambda などを全アカウントに展開、運用していきやすくなる - 標準化されたガードレールを設けて、セキュリティやコンプライアンスの要件を守る - そのうえで開発者に権限を委譲、セルフサービス化していく - multi provider でアカウントやクラウドをまたいだリソース管理が可能 - AWS アカウントをまたぐ VPC Peering も一発で貼ることができる - provider の alias を使う - 他クラウドプロバイダーとの連携もコードで表現できるのは、 terrafrorm の長所