bitFlyer Advent Calendar 2022の18日目のエントリです。
こんにちは。最近はお家時間のQoLを上げるためDIYにハマって、玄関に棚を増設したりしている、bitFlyer SRE部の遠地(とおち)です。
本記事では、Terraform CloudをAzure向けに構築しましたのでその知見をシェアしたいと思います。
tl;dr
- 「開発と運用の職務分離」や「最小権限の原則」のために、Terraform Cloudの設定自体をコード化
- いくつかの落とし穴回避ポイント
- ドメイン
app.terraform.io
を社内プロキシの対象から外す - Azure DevOpsのApplicationの追加はProject Collection Administrator権限を持ったユーザで行う
- Terraform CloudのユーザはActive Directory側で定義
- ドメイン
- Terraform Cloudにprojectの概念が欲しかった日々だった
背景
令和ちゃん四さいが気圧スライダーで遊んでいる昼下がり。とあるSREエンジニアは頭を抱えていました。サービス数が増えてきたので、terraformを触る人が増えてほしいなぁ、と。
当社においてマイクロサービス移行プロジェクトが目下進行中でした。そうです、マイクロサービス化した分だけ、クラウド上で管理するインフラも増えていくやつです。そこで、SRE部はボトルネックとならないよう、インフラをterraformコード化して、開発チームへ管理を委譲してきました。
しかし、terrformリポジトリが増えるにつれ、だんだんとCI/CDとtfstateの管理や、ワークフローの説明の負荷が増えてきます。かくして、
「Terraform Cloudを導入しよう! みんながもっと簡単に使えるように!」
というビッグウェーブは必然的に訪れ、PoCは幕明けたのでした。
要件
当社の業種は金融系ですので、原則としてしっかりとしたアクセス制御が求められます。
- 開発と運用の職務分離
サービスの開発をする人と、デプロイ・保守する人を分ける。 - 最小権限の原則
最低限必要なアクセス権限だけを付与する。
また、下記のような環境を前提に構成します。
- クラウドはAzureを使用
- Active DirectoryでSSO連携
つまり「開発と運用の職務分離」や「最小権限の原則」の要件を満たしつつ、Active DiretoryでSSO連携したTerraform Cloudから、Azureのリソースを構築したい、ということになります。
構成の検討
「開発と運用の職務分離」のため、開発チームと運用チームを設定するとします。開発チームは検証環境にのみアクセスでき、運用チームは検証および本番環境にアクセスできます。
想定できるTerraform Cloud構成としては、下記の2つから選択することになるかと思います。
- 2つのorganizationを使って根本から分離
- 1つのorganization内でチームの機能を使って分離
下記の表のようなことですね。
複数organization構成 | 単一organization構成 | |
---|---|---|
Organizations | 開発チーム, 運用チーム | - |
Teams | - | 開発チーム, 運用チーム |
複数organization構成だと、明確に分離できそうなので安心なのですが、一方で単一organization構成だと、下記のようにメリットが多いです。
- 開発チームは本番環境のterraform planの結果を同一organization内で確認できる
- Registry moduleが一箇所で済む
- Organization毎に発生するライセンス料を節約できる
よって当社では、単一organization構成を選択しました。そして、チーム分けをしっかり運用するために、Terraform Cloudの設定をコード化し、そのためのCI/CD環境も構築していきます。
構成案
単一organization構成でチーム分けをする構成です。
- Active DirectoryでSSO連携します。
- Active Directoryのgroupと、Terraform Cloud上のteamを対応させます。
- Terraform Cloudのteamごとのアクセス制御をコード化し、Azure DevOpsにCI/CDパイプラインを構築します。
手順
Active DirectoryでSSO連携
Microsoft Azure AD - Single Sign-onを参考にSSO連携を構築します。
もし社内からのインターネットアクセスに、社内プロキシなどを使用している場合で、認証のうまく行かない時は、ドメインapp.terraform.io
を対象から外しましょう。
Active Directoryのgroupと、Terraform Cloud上のteamを対応させる
Active Directoryの設定
Microsoft Azure AD - Single Sign-onの「Team and Username Attributes」に項に説明があるものの、理解するのにActive Directoryの知識が前提として必要で難易度が高いです。ですので、下記に実際の構築手順を示します。
Enterprise Application › シングル サインオン › 属性とクレーム › 編集
「グループ要求を追加する」をクリックします。
「すべてのグループ」を選びます。
「グループ要求の名前をカスタマイズする」をチェックし、「名前」にMemberOf
と入力し、「保存」をクリックします。
Terraform CloudでSSO team IDの設定
Active DirectoryのgroupのObject ID
をメモしておきます。
Terraform Cloud › Organization Settings › Teams
「SSO team ID」にObject ID
を入力して「Update team」ボタンを押します。
これをチームの数だけ繰り返し設定してください。
以上で、Active Directoryのgroupと、Terraform Cloud上のteamを対応させられたはずです。SSOでサインインして確認してみましょう。
Terraform Cloudのteamごとのアクセス制御をコード化
それでは、Azure DevOpsのPipelinesから、Terraform Cloudの設定を行えるようにしていきましょう。
VCS providerの追加
Azure DevOps Services - VCS Providers - Terraform Cloudを参考にVCS providerを追加します。
Azure DevOpsのApplicationの追加はProject Collection Administrator
権限を持ったユーザで行ってください。そうしないと、追加したVCS providerにwebhookを作成する権限がなく、CI/CDからTerraform Cloudのworkspaceを作成できなくなります。
Terraform Cloudトークンを生成
API Tokens - Terraform Cloud を参考にして、管理体制に合うTerraform Cloudのトークンを生成し、Terraform CloudのCI/CDパイプラインから環境変数TFE_TOKEN
として参照できる場所に格納します。(当社ではAzure Key Vaultに格納しています。)
VCS Providerを追加
Azure DevOps Services - VCS Providers - Terraform Cloudを参考にして、Azure用のterraformコードの置いてあるバージョン管理システムを登録します。
Azureの認証情報の設定
Terraform CloudのVariable Setsに、Azureリソースを操作するためのService Principalの認証情報を入れます。
ARM_SUBSCRIPTION_ID
ARM_TENANT_ID
ARM_CLIENT_ID
ARM_CLIENT_SECRET # sensitive attributeとして追加
検証環境と本番環境とで、それぞれ定義します。
Terraform Cloudのteam, workspace, variable setsのアクセス制御をコーディング
TFE providerを参考にしつつ、アクセス制御をコーディングしましょう。
これでTerraform Cloudから、Azureのリソースを構築する準備が完了しました🎉
解説
なぜコード側ではなくActive Directoryによってチーム分けをするか
Terraform Cloudにおいて「organization membership IDが新しく振られてしまう問題」というものがありました。
例えばtfe_organization_membershipであらかじめユーザの所属状況を定義しておいたとします。その後、ユーザが初めてSSOサインインした際に、新しくID (organization membership ID) が振られてしまい、tfstateと不整合が生じてしまう、というものです。
つまり、あらかじめ「ユーザのチーム所属状態」を定義しておくことができず、下記のいずれかの回避策を講じる必要があります。
- SSOサインインを待ってからCI/CDを走らせる
- あるいは、新しく振られたIDをterraform importする
これだと運用の難易度が高くなってしまいますので、回避策として、terraformでユーザのチーム所属を定義するのを諦め、Active Directoryのgroup側で定義するようにしました。
Azure DevOps ApplicationをProject Collection Administratorで作成する際の注意点
Azure DevOps ApplicationをProject Collection Administratorの権限を持った人に作成してもらう必要があります。
Terraform CloudのAzure DevOps連携に、そのような強い権限を持つApplicationを接続することにリスクがあるものの、一方でworkspaceの作成をコード化しないと、管理者クラスの人が全てのworkspaceの作成を対応する必要があり、とても手間です。
よって、Terraform Cloudのコードレビューなどにより、間違いのあるコードの混入を防ぐ対策が必要です。
Terraform Cloudにプロジェクトという概念が欲しかった日々だった
Terraform Cloudの感触としては、下記の図のように「project(仮)」の概念を新たに導入して、workspaceやvariable setsのアクセス範囲を簡単に定義できたら良いな、と思いました。
今回は「開発チーム」と「運用チーム」に分離する例をとりあげましたが、その例で言うと「検証環境」と「本番環境」のprojectを作っておけば、teamとprojectの関係性を定義するだけで済み、Terraform Cloudの設定をさらにシンプルにできるはずです。
エンジニア募集中です!
bitFlyerでは、このようなワークフロー改善や、サービスの安定化および効率化のための業務を日々行うSREエンジニアの仲間を募集中です。ご興味を持たれた方、ぜひご応募ください!