新卒研修環境の構築をTerraformで自動化してみた | サイバーエージェント 公式エンジニアブログ

アドテクスタジオのDynalystというチームで働いている黒崎 (@kuro_m88) です。
たまに社内で自作ドローンを飛ばしたりしています。

早いもので入社2年目になりました。つい先月まで新卒だったはずなのですが…(・・;)

今年も新卒の技術者が約60名入社し、新入社員全体の研修が終わり現在はエンジニアの技術研修が行われています。 今回はその環境構築で行ったことについて紹介しようと思います。

エンジニアの新卒研修の概要

今年の研修のゴールは「アーキテクチャをゼロから考え、実装できるようになる」というもので、研修課題は2つあります。

1つ目は現在まさに取り組んでもらっているのですが、2週間でミニブログシステムを3~4名のチームで制作してもらいます。 チームによってスキルセットが違うので、ネイティブアプリに特化するチームもいれば、バックエンドやインフラでいかにスケールしやすい構成にするか、みたいな所を工夫するチームもいるんじゃないでしょうか。

今回の研修の特徴として、各チームにAWSアカウントと検証端末(Android, iOS)を渡し、あとは自由に技術選定/計画/開発を進めてもらう方式をとっています。

2つ目はまだ秘密です。これは社外秘というより新卒にもまだ発表されていないので、書けません(笑) チームメンバーの入れ替えがあり、開発も発生すると予想されるので各AWSのアカウントのIAMユーザを再発行する必要があります。

検証端末は、社内にあるものを各チームに配布するとして、AWSのアカウントをどうやって配布しようかという事を考えはじめたのが今回のきっかけです。

要件を考える

AWSアカウントを渡して自由に使用してもらえるばいいだけなので、チームごとにAWSアカウントを発行して、クレジットカード番号を入力したあとrootアカウントのメールアドレスとパスワードの組み合わせをそのまま配布するのが一番簡単そうです。 もちろんこれはかなり危険というかリスクが大きいのでやりたくありません。

研修ですし、クラウドをがっつり触るのは初めてだという新卒も沢山いますので、できるだけミスが許容できる環境が必要です。 それらの要件を考えると、

  • 運営用のAWSアカウント (一括請求で紐付けるための親アカウントになる)
    • 運営用のIAM User (管理者権限)
    • 監視用のIAM User (読み取り権限のみ)
    • CloudTrail (運営アカウントの操作ログを保存)
    • CloudTrailのログ保存用のS3バケット
  • チーム用のAWSアカウント
    • メンター用IAM User (メンター社員が直接ログインしてサポートする必要が出た時に使う, 管理者権限)
    • チーム用のIAM User(チームのメンバーが作業する用, 管理者権限 & コスト確認のために請求情報を閲覧する権限)
    • 監視用のIAM User (読み取り権限のみ)
    • CloudTrail (チームアカウントの操作ログを保存)
    • CloudTrailのログ保存用のS3バケット

チームは12チームありますので、チーム用のAWSアカウントは12個作成します。

監視用のIAM Userを作った理由ですが、DataDogと連携させて各チームのリソースの使用状況やコストを一覧できるようにするためです。 DataDogで監視して明らかに異常な変化があればそのAWSアカウントにログインして詳細を確認した後に聞き取りをし、場合によっては直接対応することでクラウド破産その他のリスクを抑えます。

運用方法

各チームには設定済みのチーム用のIAM Userのみを渡し、AWS Console上から自由に操作をしてもらいます。 請求情報も閲覧を許可しているのでコストも各自把握して決められた予算内に収まるように調整してもらいます。

もし誤ってチーム用のIAM UserのパスワードやAPIキーを外部に漏らしてしまった場合はメンター用のIAM Userでログインし、チーム用のIAM Userを再作成します。 メンター用のIAM Userでもログインできないような事になった場合はrootアカウントでログインしてCloudTrailのログ以外の全てのリソースの削除ができるようにしておきます。

今回は初期構築を自動化するためにrootアカウントのAPIキーを発行して使っています。 AWSのベストプラクティスからするとrootアカウントのAPIキーを発行することは推奨されないのですが、少しでも手作業を減らすためにこの方法を取りました。 rootアカウントのAPIキーは社内のサーバに保存し、そのサーバからのみ作業を行うようにしました。

Terraformとの出会い

AWSで構成を自動化するサービスといえばCloudFormationですがJSONのみで設定を記述するので、構成を定義したJSONを書いたり、それを各チーム分生成するのが大変そうという印象がありました。 その次に思い浮かんだのがTerraformというツールで、名前を聞いたことがある程度だったのですが、ドキュメントのAWSの項目を読んでみて、これならある程度自動化しやすそう!と思ったのでさっそく検証に入りました。 https://www.terraform.io/docs/providers/aws/index.html

余談ですが、ProviderとしてGithubもあったのが驚きでした。GithubのOrganizationのアカウントやチームの管理もTerraformで記述できたら面白そうです。

Terraformで設定を記述

最終的に出来上がったものが以下のリポジトリにあります。

https://github.com/CyberAgent/ca-16th-training-terraform

誤って認証情報をcommitしてしまうのが怖かったので、開発を行うサーバと実際に適用をするサーバを分けて作業しました。 アドテクスタジオには個人の開発用にOpenStack環境が用意されているので、こういう時に便利です。 このリポジトリの中を役割ごとに紹介していこうと思います。

aws-admin

ca-16th-training-terraform/aws-admin

運営用AWSアカウントの設定です。

先ほど決めた要件を設定に落とし込んでいます。

IAMユーザのログインパスワードの設定ですがTerraformで設定をする方法がなかったため、provisionerとしてlocal-execを使い、ローカルでawsコマンドを叩いてパスワードを設定するようにしました。

 

1
2
3
4
5
6
resource "aws_iam_access_key" "admin_user" {
user = "${aws_iam_user.admin_user.name}"
provisioner "local-exec" {
command = "AWS_DEFAULT_REGION=${var.region} AWS_ACCESS_KEY=${var.access_key} AWS_SECRET_ACCESS_KEY_ID=${var.secret_key} aws iam create-login-profile --user-name ${aws_iam_user.admin_user.name} --password ${var.admin_user_password} || AWS_DEFAULT_REGION=${var.region} AWS_ACCESS_KEY=${var.access_key} AWS_SECRET_ACCESS_KEY_ID=${var.secret_key} aws iam update-login-profile --user-name ${aws_iam_user.admin_user.name} --password ${var.admin_user_password}"
}
}

 

aws-team

ca-16th-training-terraform/aws-team

こちらも先ほど決めた要件を設定に落とし込んでいます。 基本的には aws-admin と似た構成になっていますが、チームのパスワードは初回ログイン時に変更を強制するようにコマンドオプションがついています。 (--password-reset-required)

bin

ca-16th-training-terraform/bin

実際にTerraformの適用を行うためのスクリプトをここに記述しました。

ここが一番面倒でした。 普段Terraformを使うとなると1アカウントに対して適用することが多い思うのですが、今回は順番に12アカウントに対して適用していきます。

そうなると困るのが tfstate ファイルの扱いです。 tfstate ファイルはTerraformが扱うリソースの状態が記述されるファイルで、適用するときにはこのファイルを元にどのようなオペレーションを行うかがスケジューリングされます。

アカウントごとに読み込む tfstate ファイルを分けて扱わないと、 tfstate に記述されているリソースの状態と実際のリソースの状態に矛盾が生じて意図したオペレーションが正しく行われなく鳴ってしまいます。

そこで、

  • ローカルにある tfstate ファイルを削除する
  • tfstate ファイルをS3から読み込む
  • 適用する
  • tfstate ファイルをS3に書き出す
  • ローカルにある tfstate ファイルを削除する

このような手順で操作を行い、S3から読み書きする tfstate ファイルを操作しているチームに合せて変えるシェルスクリプトを書きました。

たとえば、1チーム分のterraform apply をするスクリプトはこのようになっています。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
export AWS_DEFAULT_REGION="ap-northeast-1"
TERRAFORM=~/terraform/terraform
bucket=$1
team=$2
pushd . > /dev/null
cd `dirname $0`/../aws-team
rm -rf .terraform
rm -rf terraform.tfstate
rm -rf terraform.tfstate.backup
${TERRAFORM} remote config -backend=S3 -backend-config="bucket=${bucket}" -backend-config="key=aws/${team}"
${TERRAFORM} plan --var-file=../conf/account_${team}.tfvars
${TERRAFORM} apply --var-file=../conf/account_${team}.tfvars
${TERRAFORM} remote push
rm -rf .terraform
rm -rf terraform.tfstate
rm -rf terraform.tfstate.backup
popd > /dev/null

 

 

このスクリプトをさらに別のスクリプトから全チーム分について呼び出すことで一度にセットアップができるようにしました。

 

conf

ca-16th-training-terraform/conf

アカウントごとのAPIキーやユーザ名等必要な変数をここに記述しておきます。

ここで記述される設定は秘密にしておかなければならないものなので、誤ってpushされたりしないように気をつけなければいけません。

実際に流してみた

実際に12チーム分の設定を流してみた動画です。 terraform plan してこれから実行される内容を表示したあとに terraform apply して実際に適用しています。 AWSのaccount idやユーザ名など、見えるのがあまりよくなさそうなものはシェルスクリプトでマスクして見えないようにしています。

3分も掛からずに適用が終ったのが分かります!!

https://www.youtube.com/watch?v=ikiG5zOsKXU

Terraformでできなかったこと

今回、全部の操作がTerraformで自動化できたわけではありません。

  • AWSアカウント自体の作成
  • クレジットカード番号の入力
  • rootアカウントのAPIキーの発行
  • IAM Userが請求情報を閲覧できるようにする設定
    • IAMの権限とは別にrootアカウントから許可する設定をする必要があります

これらの操作はrootアカウントでAWSコンソールを操作して設定をする必要があったので、人事の方に設定をお願いしました…ありがとうございます m(_ _)m

さいごに

AWSのアカウントを大量に初期設定する方法について紹介しました。 本当はAWSだけじゃなくGCP, Azureなど各種クラウドを自由に選定して使ってもらう環境を用意したかったのですが、技術研修の期間(約1ヶ月半)のわりに予算や請求の管理が大変そうだったので今回はAWSのみ、そのかわりAWSのサービス内であれば自由に選定して触ってもらえるようにしました。

弊社では技術選定が自由に任されているため、実務でも本当に色んな場面でオペレーションの自動化をしたい場面に遭遇します。

今回のようなちょっとしたアカウント管理を自動化したいという要望からオンプレやクラウド関係なくガッツリインフラの構築を自動化する仕事まで、どんどん自動化を推進する仕事に興味ある学生の方は夏前にインターンの募集が始まると思いますので、ご応募お待ちしております! https://www.cyberagent.co.jp/recruit/fresh/internship/ (2016/04/26時点ではまだ募集を開始しておりません、もうしばらくお待ち下さい)

おまけ

1チーム分を plan => apply => destroyの操作をやってみたバージョンの動画です。

https://www.youtube.com/watch?v=KvYv8NzBAtQ