こんにちは!最近 デスクセットアップ が趣味である freee AI Platform Engineering チームの JaeSoon です。 ゴールデンウィークに合わせて、リビングと作業部屋のレイアウトをまるごと組み直しました。
あれこれ動かしているうちに気づけば連休が終わっていましたが、毎日座る場所だけに作業のコンディションが目に見えて変わって、満足しています 🪑✨

私がもともと所属していた「AI駆動開発(AI-Driven Development)チーム」 は、社内のプロダクト開発組織における AI 活用を定着させる仕事をしてきました。
その結果、freee の開発組織では すでに 97% のエンジニア(残りの 3%は経営陣もしくは EM なので、ほぼ全エンジニア)が AI コーディングエージェントを日常的に使っている 状態に到達し、次の課題は自然と この成功をエンジニア組織の中だけに閉じず、Sales / CS / 企画 / 管理部門など全社へ広げること に移っていきました。
それに合わせてチーム名も AI Platform Engineering チーム へと変わりました。今や単なるAI駆動開発領域、便利 Coding Agent ツールの導入にとどまらず、業務フロー自体をAIで再定義できる技術基盤の構築へと活動領域が広がっています。
なお、freee では Claude Enterprise の全社展開にあたり、複数のレイヤーで安全性を担保する取り組みを並行して進めています。たとえば:
- Jamf を活用して各設定をエンジニア・非エンジニア双方への端末配布
managed-settings.jsonによる Claude Code の挙動制御 (危険な操作の Deny)- OpenTelemetry で Claude Cowork, Code Log を収集し SIEM に転送してモニタリング
- Claude を安全に使うための社内ガイドライン・オンボーディング整備
といった対応を組み合わせています。これらについては追って別途公開予定ですが、本記事ではその中でも「SCIM × IaC による権限設計と運用」 に絞って詳しく解説します。メインはあくまで 権限設計と IaC 運用 で、Usage Controls はその上にもう一枚かぶせた補助装置という位置づけです。
freee が AI ツールを社内に入れて運用してきたストーリーは下記の記事にまとまっていますので、合わせてご覧ください。
- 数字で振り返る freee の AI 駆動開発 - 後編 - freee Developers Hub
- AI駆動開発へ。freee は開発環境をどう進化させているか?- 前編 - freee Developers Hub
- AIエージェントCline、freeeはどうやって全社導入した? - freee Developers Hub
本記事に頻出する OneLogin (freee が社内標準 IdP として使用している製品) × Terraform ベースの権限管理基盤は、freee 社内ですでに整備済みのものであり、それ自体については下記の記事にまとめられています
developers.freee.co.jp
本記事で扱う Claude Enterprise の SCIM 連携も、この基盤の上に乗っかる形になっています。OneLogin 以外の IdP 環境であっても、本記事の設計パターン自体はほぼそのまま通用するはずです。
はじめに: Enterprise 契約後に向き合った 4 つの問い
エンタープライズ契約を結んでシートを発行した瞬間がゴールではなく、そこからが本当のスタートでした。運用に乗せてみると、「みんなが安心して触れる状態」 を維持するために、もう一枚レイヤーを足す必要が出てきます。具体的には次の 4 つの問いです。
- 誰が どこまで 触れるか (管理者権限・課金変更・SCIM 設定など)
- どの利用フレーム で渡すか (例: Claude Code を ON にするか OFF にするか、ヘビーユーザー / 一般 / 検証フレーム)
- 暴走を防ぐための 予算ガードレール をどこにどう敷くか
- 上記すべてを IaC で再現可能 な形にできるか (人間の SaaS コンソールクリックに依存しない)
この 4 つに正面から向き合うために整備したのが、本記事のメイントピックである SCIM × Custom Role による権限設計と、その IaC 運用 です。Spend Controls はその上に補助的に一枚かぶせたガードレールという位置づけで、本記事の最後で軽く触れます。
📝 補足: 本記事で扱う SCIM 連携 / Group mappings / Custom Roles / Spend controls はいずれも Claude の Enterprise プラン で提供される機能です (Team プランでは利用不可、または制限あり)。ご利用前に Anthropic 公式の Enterprise プラン案内 で最新の対応範囲をご確認いただくのがおすすめです。
整備の前提: Claude Enterprise が提供してくれるもの
Enterprise プランで使える「権限まわり」の機能を、freee 運用の観点で整理するとこうなります。
| 機能 | できること | freee での活用先 |
|---|---|---|
| SSO / SCIM directory sync | OneLogin (社内 IdP) をマスターに据え、ユーザー / グループ情報を同期 | 既存の OneLogin ベースに権限管理を一元化 |
| Group mappings | OneLogin 側のグループ名を Claude 側 Role に自動マッピング | 「グループに入れる = ロールが付く」を IaC で再現 |
| Custom Roles | 既定の Owner / Admin / User とは別に 細分化された権限プロファイル を作れる | 「Claude Code を使ってよい / ダメ」「default / ai-sandbox」などの利用フレームをグループで指定し、それに合わせたロールで表現 |
| Spend controls | 組織全体・ロール単位で予算ガードレールを設定 | 暴走時の保険、検証フレームの予算分離 |
| Usage analytics | ユーザー / Role 単位の利用状況の可視化 | 「利用フレームの見直し」「sandbox の効果計測」のインプット |
| Audit logs | 重要操作の監査証跡 | コンプライアンス・インシデント対応用 |
このツールセットの上で、設計の決めとして置いたのはシンプルです — OneLogin を唯一の source of truth とし、Claude 側の状態はそこから同期されるアウトプットとしてのみ扱う。コンソールから直接手を入れるオペレーションは、できるかぎり作らないようにしました。
User ロールではなく Custom Roles を使う
Claude Enterprise の Group mappings 設定画面では、OneLogin 側のグループ名を次の 4 種のいずれかにマッピングできます。
- Owner … 最上位の管理権限 (SCIM 設定・課金変更など)
- Admin … 組織管理権限
- User … 一般ユーザー (= デフォルトのまま渡す)
- Custom roles … 自前で定義したロール

一見すると「全員に Claude Code を渡したいなら User に紐づければいいのでは?」と感じますが、freee ではあえて User には何もマッピングせず、すべてを Custom Roles に寄せました。理由は次のとおりです。
- 「Claude Code を使う / 使わない」を権限レベルで分離したかった
- User ロールは便利な一方で、「全員に同じ権限を一律配布」しかできません。
- Claude Code は強力ですが、利用形態によっては別途レビュー・トレーニングを挟みたいことがあります。
- Custom Roles なら「Claude Code 有効版」と「Claude Code 無効版」を、同じ利用層に対して 別ロールで提供できます。
- 利用層 (layer) と機能スイッチを直交 (orthogonal) にしたかった
- 後ほど触れますが、freee では「default / ai-sandbox」という 利用層 と、「claude-code 有効 / 無効」という 機能スイッチ の 2 軸で組み合わせています。
- 今後 (例: ヘビーユーザー専用ラインなど) 層を増やすことになっても、この 2 軸構造のまま自然に拡張できる土台になっています。
- これを User 1 種だけで表現するのは無理で、Custom Roles 前提でないと成立しません。
- 既存ユーザーの「知らないうちに昇格」を防ぎたかった
- 仮に今後 User ロール側にデフォルト権限が追加されても、誰も User に入っていなければ影響はゼロ。
- 「明示的にロールに入っている人だけがその権限を持つ」という状態を強制できます。
最初に設計した時点では、Anthropic 側にデフォルトで 「default」という名称でいわゆる「誰でも使えるフレーム」が用意されていた 状態でした。これを尊重しつつ、freee 側で必要となる利用層を増やしていく形で命名を統一しました (詳しくは次のセクション)。
グループ設計: 「利用層 × Claude Code 有無」の 2 軸
Custom Roles を使う方針を決めた上で、freee では以下の 2 軸でグループを設計しました。
軸 1: 利用層 (layer)
| Layer | 想定ユーザー像 |
|---|---|
default |
業務で Claude を使う一般ユーザー (圧倒的多数) |
ai-sandbox |
freee の AI 特区 制度に合わせたフレーム。一般ポリシーから一旦切り離して、安全に新ツール・新機能を先に試せる限定エリア |
将来的にヘビーユーザー専用ラインなど別の利用層を切り出す可能性もありますが、現時点では運用は default と ai-sandbox の 2 層に絞っています。
ℹ️ AI 特区とは: freee 社内ですでに存在する制度で、Cline 導入記事 で初めて詳しく紹介されています。一文でまとめると 「全社展開するにはリスクが大きいが試してみたい — そんな AI ツールを安全・迅速に検証するための制度。特区として認められたチーム・メンバーに限り、サンドボックス環境など定められた条件下での利用を許可する」 というのがコアの定義です。本記事の
ai-sandboxCustom Role は、この制度を Claude 側の権限レイヤーでそのまま形にした ものに該当します — 特区として認められたメンバーだけがこのロールに紐づいており、一般ライン (default) の安定性を守りながらも、新機能・新モデル・実験的な運用パターンを先にぶつけられるようにしています。
軸 2: Claude Code の有効 / 無効
| Variant | 用途 |
|---|---|
*-claude-code |
Claude Code を含む全機能 ON |
*-no-claude-code |
Claude Code は無効、その他の Claude 機能のみ |
この 2 軸目は、ざっくり言えば 「Claude Code を日常的に回す人」と「主に claude chat UI ないし claude cowork の形で Claude を使う人」 の違いを表す軸でもあります。職種に例えると前者がエンジニア、後者がノンエンジニア寄りの分布になりがちですが、最近では ノンエンジニアの方も AI を活用して社内ツールを自分で作り始めており、この境界そのものがどんどん薄くなっているので、私たちは職種ではなく 「Claude Code を ON で使うか」 という行動基準でラインを引きました。同じノンエンジニア部署でも Claude Code を本格的に回し始めた人は *-claude-code 側に、同じエンジニアでも一旦チャット UI 中心に使っている人は *-no-claude-code 側に自然に移れる設計です。
この区分は権限の他にもう一つ意味を持つ部分があります。利用パターンが違えば 1 人あたりに必要な予算水準も結構変わる — Claude Code を本格的に回す側はトークン消費が桁単位で大きくなるので、同じツールだからといって同じ予算ラインにまとめると、片方が常に足りないか、もう片方が過剰割り当てになっている状態になります。*-claude-code / *-no-claude-code をロール単位で先に分けておけば、後ろで触れる Spend Controls / Usage analytics 側で 異なる基準線で予算を引ける余地 が自然に確保できます。
これらを組み合わせて freee 側で運用している Custom Roles は、次のセットになりました (<org-id> は組織ごとに発行される UUID)。
anthropic-claudeai-<org-id>-owner anthropic-claudeai-<org-id>-admin anthropic-claudeai-<org-id>-default-claude-code anthropic-claudeai-<org-id>-default-no-claude-code anthropic-claudeai-<org-id>-ai-sandbox-claude-code anthropic-claudeai-<org-id>-ai-sandbox-no-claude-code
ℹ️ 命名規則は、Anthropic が初期に設定していた
default名のグループに合わせる形でai-sandboxを派生させました。「すでに Anthropic 側に存在する命名パターンに合わせる」方が、コンソール上の視認性と SCIM 設定の追跡性が高いと判断したためです。
構成の全体像: OneLogin (IdP) → SCIM → Claude Roles

ポイントは、「グループに入れる」=「Custom Role が付く」=「Claude の中で権限が変わる」 という 1 行のパイプラインを、ボタンクリックではなく OneLogin 上の Role 所属だけで 表現している点です。
IaC 設計: 「IaC が所有するもの」と「人が所有するもの」を分ける
すべてを IaC に押し込めば理想的だ、と言いたいところですが、現実には次の事情がありました。
- OneLogin Terraform プロバイダー側に、Role / App Rule そのものを作る API が安定的に公開されていない / ワークスペース実行 Role にその操作権限がない
- Claude 側の SCIM Group は Anthropic 側で自動生成され、OneLogin の App Rule (
set_groups) の発火によってはじめて紐づく
そこで、責任を明確に分けました。
| 対象 | オーナー |
|---|---|
| OneLogin Role 定義そのもの | 管理者が OneLogin コンソールで 1 回作成 (out-of-band) |
OneLogin App Rule (set_groups で SCIM Group 値を push) |
管理者が OneLogin コンソールで 1 回作成 (out-of-band) |
| Role に対するユーザー所属 | IaC が所有 (Terraform で管理) |
こうすると、Terraform 側のコードは 「ロールに誰が所属しているか」だけ をシンプルに表現すればよくなります。再利用しやすいモジュールに切り出して、各ロールに薄いラッパーを置きました。
# モジュール側: Role ID とユーザーリストだけを受け取る。 # caller がメールアドレスでメンバーを書けるよう、モジュールの中でメール → OneLogin user ID に解決する。 locals { email_to_id = { for k, u in var.users : u.mail => u.id } user_ids = [for e in var.user_emails : local.email_to_id[e]] } resource "onelogin_user_role_attachments" "attach" { role_id = var.role_id users = local.user_ids }
# 呼び出し側: 利用層ごとに 1 ファイル (default / ai-sandbox) # owner と admin は運用上 1 まとまりで近くに置きたいので、別途同じファイルにまとめる (ただしモジュールは分離) module "claude-default-claude-code" { source = "../modules/claude-role" role_id = local.claude_roles["default-claude-code"] users = data.terraform_remote_state.onelogin_mapping.outputs.users user_emails = [ local.users.<...>.mail, # DO NOT DELETE: new users will be inserted above this line by add-claude-user.js [role: default-claude-code] ] }
ロール ID は locals.tf にまとめておき、コードからはそれを参照する形にしました。
locals { claude_roles = { "default-claude-code" = "<id>" "default-no-claude-code" = "<id>" "ai-sandbox-claude-code" = "<id>" "ai-sandbox-no-claude-code" = "<id>" "owner" = "<id>" "admin" = "<id>" } }
こうして「OneLogin コンソール所有 (Role 定義 / App Rule)」と「Terraform コード所有 (Role 所属)」をプロバイダー機能の境界に合わせて分けておくと、IaC 側は Role ID という安定した参照点だけを握っていればよく、後ろが多少変わってもユーザー所属レビューのフローは崩れません。
段階的なロールアウト: 「壊れたら戻せる順序」で適用する
新しい SCIM ロールを一度に適用するのは怖いので、PR を スタック (積み重ね) にして段階的に進めました。
- canary PR —
ownerロールだけを最初に作る- 利用者数が最小 (数名) で影響範囲が極小。
owner権限も関連する全役員・管理者に一括付与せず、実際に owner レベルの操作が必要なメンバーだけに絞って 付与しました。owner は SCIM 設定・課金変更などの強い権限を持つので、「管理ライン = 自動で owner」という一律付与を避けて、具体的に運用責任のある人だけを名簿に上げています。- App Rule の
set_groupsアクションが正しく解釈されるか をここで初めて検証。 - 万が一アクション名が間違っていても、このロール 1 個の apply だけが失敗し、他には波及しない。
- 想定どおり動けば、Claude 管理画面に SCIM バッジ付きの新規 Group が自動生成されます。
- admin ロールを追加
- canary がグリーンになったのを前提に、Admin の付与を別 PR で出します。
- 「暫定付与」「期限見直し」といった運用メモはコード上にインラインコメントで残します。
- 既存ユーザーの全量マイグレーション (3 PR をスタック)
- 本運用ユーザーの大半 (~1,000 名規模) を、レガシーの単一ロールから「層 × 機能スイッチ」の Custom Roles に移行。
- 1 PR ですべて移すのではなく、(a) ai-sandbox / owner / admin → (b) default 前半 → (c) default 後半 + 旧ロール解体 に分割。分割の理由は 2 つあります。
- レビュー可能性 — 一度に 1,000 人近い attachment 変更が入っている diff は、事実上レビュー不能。
- API 側の限界 — OneLogin Terraform Provider は 前掲記事 でも触れられているとおり、大量の attachment 変更を一度に適用すると Timeout / Too Many Request Error で apply が途中で落ちやすい 特性があります。一度に全部適用して途中で失敗すると、「どこまで反映されてどこから抜けたか」を追うコストが大きくなりすぎるので、グループ単位で細かく分けて、apply が安全に終わる単位で PR を切る 方が結果として安全でした。
- 各 PR で「移動前後でユーザー総数が一致するか」「重複や抜けがないか」を CSV と diff で機械的に検証。
- レガシーロール (
User相当の単一ロール) の物理削除- 全員の移行が確認できた段階で、最後の PR で空になった旧ロール定義を削除。

SaaS 連携の IaC では「壊れた瞬間に何が壊れたか分かる粒度」で PR を切るのが特に効きました。canary を最小スコープに切ったおかげで、SCIM 連携部分の挙動検証 → 全量移行という順序を安全に通せましたし、本運用マイグレーションでも「レビュー可能な粒度」と「API が一度に安全に処理できる粒度」のうち小さい方に PR サイズを合わせて、適用の途中失敗そのものが起きないようにしています。
日常運用: 追加・削除も IaC PR フローに乗せる
権限基盤を IaC に寄せた以上、日常の「ユーザーを増やす / 減らす」も同じレールに乗せる のが鉄則です。freee では GitHub Actions の workflow_dispatch で
- 対象 Custom Role の選択 (drop-down:
default-claude-code/ai-sandbox-claude-codeと、それぞれのno-claude-code版) - 追加 / 削除するユーザーのメールアドレス (カンマ区切り)
- 利用目的 (PR 本文・コードコメントに記録)
を入れるだけで
- 該当の Terraform ファイルにユーザー参照を DO NOT DELETE マーカー の直前に挿入
terraform fmtを適用- 自動で PR を作り、申請者・対象ロール・対象ユーザー・利用目的を Body にまとめる
という処理が走るようにしてあります。レビュアーは IaC 側で 「正しい層 × 正しい claude-code 有無の組み合わせか」 だけを見ればよく、SaaS コンソールでのオペレーションは原則発生しません。

「コードに反映 → PR レビュー → apply」のフローを崩さないことが、過去のインシデントから学んだ最大の教訓でした。コンソールから直接編集できる権限を狭め、必ず PR を通すことで、「いつ / 誰が / なぜ」追加したかが永続的に残ります。
locals { claude_seat_limit = XXXX } check "claude_seat_limit" { assert { condition = length(local.claude_unique_users) <= local.claude_seat_limit error_message = format( "Claude seat limit exceeded: %d users are assigned, but the limit is %d.", length(local.claude_unique_users), local.claude_seat_limit, ) } }
また、シート数の上限管理も同じ IaC の仕組みに組み込んでいます。check_claude_seat_limit.tf では Terraform の check ブロックを使い、全 Custom Role に割り当てられたユニークユーザー数が契約シート上限を超えた場合に Terraform Plan の段階で自動的にエラー を出すようにしています。
これにより「申請 → PR → plan → apply」のフロー上で、うっかりシート超過状態を本番に適用してしまうことを防げます。人間がコンソールで気づく前に、IaC 側で検知できるのが利点です。
補助のガードレール: Usage Controls
ここまでが本記事のメインである権限運用の話です。最後に、その上に薄く一枚かぶせている Usage Controls にも軽く触れておきます。これは新たに「基盤を構築した」種類の話ではなく、Anthropic 側が提供してくれている機能を 権限設計と粒度をそろえてオンにしている 程度の位置づけです。
- 組織全体に月額予算を設定 (突発的な暴走への保険)
- 必要に応じて Role 単位で予算を分離 (特に
ai-sandbox系は 検証目的の予算フレーム として明示的に切る) - 先ほど触れた
*-claude-code/*-no-claude-codeの予算基準線の違いを意識して、1 人あたり必要予算の感覚を 2 グループで別に取る (Claude Code を本格的に回す側はトークン消費が桁単位で大きくなるので、同じラインで括らない) - Usage analytics を週次で確認し、
default/ai-sandboxの比率やno-claude-code側の利用傾向を見ながら、必要に応じて層の見直し / Role 移動を提案
「上限」と書くと制限的に聞こえますが、「ここまでなら安心して使ってよい」という予算 (Budget) として扱う のが私たちのスタンスです。SCIM で配布した権限運用の上に、Usage Controls がもう一枚軽く支えてくれることで、ようやく「みんなに渡しても大丈夫」と言える状態になります。


振り返って学んだこと
- 「みんなに渡す」のゴールは配った瞬間ではなく、配り続けられる状態を作ったとき
- 個別申請を捌いていく運用には限界があります。SCIM × IaC × 自動 PR で「申請 → コード反映 → 監査証跡」を一直線にできたのが効きました。
- User ロールではなく Custom Roles に寄せたのが正解だった
- 2 軸 (利用層 × Claude Code 有無) を表現する余地が、後から効いてきました。
- 「あとで層を増やす」「あとで Claude Code 無効版を作る」が壊れずに追加できる構造です。
- canary を最小スコープに切ることのリターンは大きい
- SaaS API 連携の不確定要素は、最初の数名にぶつけにいく方が結果として一番速く・安全。
- コンソール所有 / コード所有の境界はプロバイダー機能に従う
- 「全部 IaC」を盲目的に追わず、プロバイダーが支えてくれる範囲だけ IaC で持つのが現実的でした。
おわりに
Claude Enterprise を「契約したらおしまい」ではなく、全社員が安心してフルに使える基盤 にするためにやってきたことを、駆け足でご紹介しました。
AI Platform Engineering チームのミッション自体が「プロダクト開発チームだけでなく、全社が安全に AI を使える状態」を作る方向に移っているので、権限・予算・トレーシング・社内ガイドラインといった足元を、ツールが進化するスピードに置いていかれない形で整え続けていく予定です。本記事で扱った SCIM × IaC の権限運用もその一片で、同じ「Enterprise 契約後の運用設計」で悩んでいる方の参考になれば嬉しいです。
そんな AI Platform Engineering チームでは、全社が安全にAIを使えるプラットフォーム作りをリードしてくれるエンジニアを募集しています。
本記事で紹介したような SCIM × IaC による権限設計・ガバナンス はもちろん、社内 AI ワークフロー基盤(n8n)の構築・運用、BigQuery × Vector DB を活用したコンテキスト基盤の設計、各部門への AI 活用 Enabling など、「全社 AI-Native 化」を技術的に支えるポジション です。
「AI を使う組織」ではなく「AI と共に動く組織」を作ることに興味がある方、ぜひ話を聞きに来てください!
それではみなさま、よいデスクテリアとよい AI 活用を 🛠️🤖
