はじめに
クラウドワークスのインフラエンジニアの森田(@minamijoyo)です。
クラウドソーシングのクラウドワークスではサービスを提供するためのサーバ群をAWS(Amazon Web Services)で運用しています。
AWSではIAM(Identity and Access Management)という権限管理の仕組みを利用して、複数の担当者をグループで管理して必要な権限を割り当てることが可能です。 IAMはAWSを使う以上は避けては通れない機能ですが、すこぶる使い勝手が悪く、IAMポリシー編集とかやったことある人は分かると思いますがツライです。
何がツライかというと、
- 何も考えずに弱い権限のユーザとしてReadOnlyAccess権限とかだけ渡すと、自分のパスワード変更すらできない
- 個別に権限付与しようとすると権限の種類がいっぱいある上、サービス増える度に追加されるのにもかかわらず、全サービスの権限一覧表が公式ドキュメントに見当たらない。
- 権限を変更する権限を管理者以外には与えたくないので、権限を変更したい人じゃなくて管理者権限を持っている人が都度ポリシー編集作業せざるをえなくて開発スピードが落ちる
- 管理者が一人じゃないと、誰が、いつ、どんな理由でポリシーをいじったのかよく分からんくなってカオス
- ポリシーの編集はAWSのマネージメントコンソールからやるのだけど、ブラウザ上のポリシーエディタでJSONを編集する苦行がツライ
- ポリシーの履歴は5世代保存されているが、差分表示ができないとかありえない
- ポリシーの履歴が上限になると、手動で履歴を削除しないとポリシーを編集して保存できなくなるとか不便過ぎる仕様をなんとかしろ下さい
というわけで、根性ではなく仕組みで解決しようと思い、以前Qiitaにこんな記事を書きました。
TerraformでAWSのIAMユーザのグループポリシーを管理する
雑にまとめると、
- TerraformでIAMポリシーをコードとして管理すれば、
- AWSのコンソールでJSONを編集するという苦行から開放され、
- gitで管理できるようになって権限を欲しい人がプルリクエストベースで依頼することができるようになって、
- 権限変更の差分がレビューできて、記録にも残るし、いいコトづくしですしおすし。
という作戦です。
上記の記事では、
- TerraformでIAMポリシーをコード化する方法
- Terraformを使ってAWSのリソースに手動で反映する方法
- Terraformの状態管理ファイル(terraform.tfstate)をAtlasに保存する方法
などについて説明しています。
この記事では、より発展的な内容として、
- GitHubとAtlasを連携させた、プルリクエスト時の変更リソースチェック(terraform plan)や、masterブランチへのマージトリガでAWSへの反映(terraform apply)の自動化
- 具体的なグループ分けの例
などより実践的な内容について説明しようと思います。
現状Atlasの具体的な使い方を日本語で解説している記事が全然見当たらないので、Atlasの設定はできるだけスクショ多めでお送りします。
AtlasとGitHubの連携
Terraformでコード化されたIAMグループのメンバーやポリシーなどを変更した場合、terraform apply
コマンドでAWSに反映する必要があります。
毎回手動でやるのはめんどくさいので、Terraform化されたコードをGitHubのリポジトリにおいて、Atlasと連携させることで、 プルリクエスト時の変更リソースチェック(terraform plan)や、masterブランチへのマージトリガでAWSへの反映(terraform apply)を自動化できます。
AtlasはHashiCorp製のインフラを統合管理するプラットフォームです。
とりあえず今のところは(?)無料で使えるので、アカウントがなければ取得してください。
(※2016/5/26追記:HashiCorp公式のAtlasはベータ期間が終了して有料化されたようです。New Interface Design, User Experience, and Pricing for Atlas - HashiCorp)
以降の説明では、既にAtlasでTerraformの状態管理ファイル(terraform.tfstate)を管理している状態を前提としているので、準備がまだの場合は先ほどの記事を参考に設定して下さい。
TerraformでAWSのIAMユーザのグループポリシーを管理する
GitHub連携の有効化
Atlasにterraform.tfstateを登録すると上部の「Environments」のメニューに terraform remote config
で登録した名前が表示された状態になっています。
ここでは minamijoyo/iam-terraform-example
という設定を例に説明していきます。対象のEnvironmentsをクリックして設定画面を表示します。
「Settings」のメニューをクリックします。
いくつか設定項目が並んでいますが、Terraform Configurationという項目に「Import Terraform Configuration from GitHub」というリンクがあるのでクリックします。
初めてAtlasとGitHub連携の設定をする場合は、このタイミングでGitHubのOAuthの認証画面が出てアクセス許可が求められるはずなので、GitHubへのアクセス許可を承認して下さい。 (この説明用のスクショを取ってるときは、既に私のGitHubユーザで他のリポジトリをAtlasと連携してしまっており、確認画面が出なかったのですが)
これはGitHubにpushしたタイミングなどでAtlasに通知するためのWebhookを設定したりするのに権限が必要だからです。
GitHubへのアクセス許可を承認すると、以下のようなAtlas側のEnvironmentsとGitHubのリポジトリを対応付ける画面になるので、該当のEnvironmentsとGitHubのリポジトリ名を指定して下さい。
Terraform関連のファイルがリポジトリ直下になくサブディレクトリなどに入っている場合は「Path to Directory of Terraform files」のところで調整して下さい。 今回は特に不要なのでデフォルトの 「/」のままにしてあります。 設定ができたら、「Import Configuration」ボタンをクリックします。
「Changes」のメニューにコミットが見えているのが確認できます。
また「Integrations」のメニューでGitHub Integrationのところにリポジトリ名が設定されていれば問題ないです。
自動terraform applyの設定
デフォルトだとterraform planはプルリクエストのタイミングで自動実行されますが、terraform applyは自動で実行されません。 「Settings」のメニューから「Auto apply」を指定して「Save」ボタンを押します。
AWSアクセスキーの設定
このままだと、AtlasからAWSリソースへのアクセス手段がないので、AWSのアクセスキーをAtlas側に設定する必要があります。
まず、AWSのマネージメントコンソールからAtlas用に新規ユーザを作成し、「Permissions」の「Attach Policy」から「IAMFullAccess」を許可します。 (※IAMFullAccessをAtlasに許可するのに若干の抵抗はありますが、特定ユーザのAPI呼び出し履歴を確認するのは可能ですし、万が一問題があればアクセスキーの無効化はできます)
また、「Security Credentials」の「Create Access Key」からAWSのアクセスキーを発行します。
次に、Atlasの設定画面に戻り、「Variables」のメニューで環境変数を設定します。
「Environment Variables」の箇所に、「AWS_ACCESS_KEY_ID」と「AWS_SECRET_ACCESS_KEY」の項目を追加し、先ほど発行したアクセスキーを設定します。
Slack通知の設定
ついでにAtlasでterraform applyしたタイミングなどでSlackに通知を送りたい場合は、「Integrations」のメニューの「Run Notifications」のところに 各種通知イベントや、SlackのWebhookURLやチャネル設定をする箇所があるので、適宜好みで設定して下さい。
実際にプルリクエストしてみる
適当にポリシーをいじって、プルリしてみました。
プルリすると自動でterraform planが実行され、失敗すると、このように×印が付きます。(えっ、なんでプラン落ちてんの!?想定外(。◉ᆺ◉)
×印をクリックするとterraform planの結果が確認できます。
AWSのregionが指定されてないとか言われてますね。 なんだろう手元で実行したときは出てなかったんですけど、よしなにaws configureの設定を読んでたので大丈夫だったのかもしれません。
とりあえず 別ブランチで試しにproviders.tf
というファイルを作って、以下のように明示的に指定しておいたらterraform plan通るようになったので
provider "aws" { # AWSのAPIのエンドポイントなだけでIAMの設定自体はグローバルで有効となる region = "ap-northeast-1" }
rebaseしてforce pushしなおしました。
今度はちゃんとterraform planがpassしました。緑色のチェック印をクリックするとplanの結果も見れます。
1つのポリシーが変更されていることが分かります。
ただ、AtlasというかTerraformの問題なんですが、JSONが1つの文字列になっててすごい見づらいのが若干残念です。
ここで確認できるのはあくまでも文法間違いでplanが失敗しないかとか、変更した認識のないリソースが変更されていないかの確認ぐらい。
自動化されていれば基本的にmasterブランチがAWSの状態と一致しているはずなので、ポリシーのJSON自体の差分はGitHubのdiff表示の方で確認しましょう。
差分が問題なければプルリをマージすれば terraform apply
してAWSに反映されます。
「Changes」のメニューからもAPPLIEDになっていることが確認できます。
Slack通知の設定をしていれば terraform apply
が完了したタイミングで通知が来ます。
以上でmasterブランチにマージしたタイミングでAWSに自動反映することができるようになりました。
グループ分けの例
最後にIAMユーザのグループ分けの方法について、ちょっとだけ説明しておきます。 グループ分けの方法は、組織の構造などに大きく依存するので、あくまでもこーゆー分け方もあるよレベルの一例ですが、 現状、以下のようなグループ分けをした上で、1ユーザが必要に応じて複数のグループに所属することで、権限を得る仕組みで運用をしています。
- 共通ユーザグループ
- 管理者グループ
- 所属する人:IAMを変更する必要がある人
- できること:なんでもできる(root権限を除く)
- 経理担当者グループ
- 開発者グループ
- 所属する人:エンジニアで管理者以外の人
- できること:IAMや一部リソースに機能制限があるがそれ以外は日常必要な大体のオペレーションはできる
- テクニカルサポートグループ
- 所属する人:お問い合わせの調査などで決済ログなど一部のセンシティブな情報を見る必要がある人
- できること:特定のログがバックアップされてるS3バケットへのアクセス
- インフラ開発者グループ
- 所属する人:インフラ開発でIAMロールの操作などセキュリティ的に強い権限が必要な人
- できること:IAMロールを付与したEC2インスタンス生成や、Lambdaの作成など
グループの分け方に正解はないと思いますが、グループのメンバーやポリシーがTerraformでコード化されてGitHub管理されていれば、 状況の変化に応じて柔軟に改善していくことが可能なので、まず運用を初めてみてから調整していくのがよいかと思います。
おわりに
Terraform+Atlas+GitHubでAWSのIAMユーザのグループポリシーをいいかんじに管理する方法について説明しました。
クラウドワークスでは自動化が大好きなエンジニアを募集しております。