RBAC入門:Re:Earthはどのように認可を実現しているか

2026-05-14

RBAC入門:Re:Earthはどのように認可を実現しているか

1. ロールベースアクセス制御(RBAC)を理解する

RBACとは何か、なぜ重要なのか

ロールベースアクセス制御(RBAC)は、ユーザーが組織内で担う「役割」をもとに、リソースへのアクセスを管理する仕組みです。ユーザー一人ひとりに権限を直接ひもづけるのではなく、まずロールに権限をまとめ、そのロールをユーザーに割り当てる、という考え方をとります。アプリケーションが大きくなってくると、個人単位で権限を貼って回るやり方はすぐに限界がきますし、ミスも起こりやすい。だからこそ、こうしたロール経由の発想が効いてきます。

RBACの中核コンポーネント:ロール、権限、ユーザー

RBACの登場人物は大きく3つです。権限のレベルを表す「ロール」、リソースに対して許される操作を表す「権限」、そして実際にロールが割り当てられる「ユーザー」。この3者の関係をうまく組み合わせると、最小権限の原則に沿った見通しのよいセキュリティモデルがつくれます。

モダンアプリケーションでRBACを導入するメリット

RBACの良さは、権限をロール単位でまとめて扱える点にあります。これだけで管理がぐっと楽になりますし、付け間違いも減るのでセキュリティ的にも安心です。誰がどの権限を持っているか後から追いやすくなるので、監査やコンプライアンス対応もスムーズ。組織のかたちとアクセス権が自然に揃うので、運用効率も上がります。ユーザー層が幅広いモダンなアプリケーションにとっては、セキュリティ面でも拡張性の面でも頼れる選択肢です。

RBAC導入でよくある課題

もちろん、いいことばかりではありません。気づくと細かいロールを作りすぎてしまう「ロール爆発」、組織変更のたびにロールを追従させる手間、ロール継承の階層が複雑になっていく問題、時間帯による制限のような横断的な要件への対応など、実際に運用しはじめると壁にぶつかるポイントはいくつもあります。

2. 認可システムの進化

従来のアクセス制御モデル

初期の頃の認可システムは、任意アクセス制御(DAC)や強制アクセス制御(MAC)といったシンプルなモデルが中心でした。DACはリソースの持ち主自身がアクセス権を決めるやり方で、MACはセキュリティ分類に基づいて強制的にアクセスを縛るやり方です。小規模なシステムならこれで十分でしたが、複雑なアプリケーションに必要な柔軟さまでは持ち合わせていませんでした。

ロールベースシステムへの移行

組織が複雑になるにつれて、こうした従来モデルでは手が回らなくなり、そこに登場したのがRBACです。ユーザーと権限のあいだに「ロール」というクッションを挟んだことで、アクセス管理がぐっと直感的になり、組織のかたちにも合わせやすくなって、管理の手間も大きく減りました。

RBACから属性ベースアクセス制御(ABAC)へ

RBACで多くの問題は片付きましたが、モダンなアプリケーションはさらに状況に応じた細やかな判断を求めるようになりました。そこで出てきたのがABAC(属性ベースアクセス制御)です。ユーザー属性、リソースの特性、その時の環境条件など、いろいろな属性を組み合わせて判断できるようになり、より精密で動的なアクセス制御ができるようになりました。

Policy as Code:モダンなアプローチ

最近のトレンドは、ポリシーを「コード」として扱うアプローチです。ソフトウェア開発のやり方をそのままアクセスルールの管理にも持ち込もう、という発想ですね。Cerbosのようなツールが代表例で、認可ロジックをアプリ本体から切り離せるので、サービスをまたいでも一貫した制御がかけられて、しかも変更履歴を追いやすいのが利点です。

3. Re:Earthの認可ニーズ

Re:Earthプラットフォームの紹介

Re:Earthは、コードを書かずに3Dデジタルツイン環境や地理データを作成・共有・可視化できる、Webベースの地理空間プラットフォームです。個人クリエイターからエンタープライズチームまでユーザーの幅が広く、それぞれがプロジェクト、データセット、可視化ツールに対して違うレベルのアクセスを必要とします。この多様さがあるからこそ、セキュリティと協業のしやすさを両立するうえで、認可がとくに大切な要素になってきます。

Re:Earth特有の認可要件

Re:Earthのような地理空間プラットフォームには、一般的なWebアプリではあまり出てこない認可の悩みがあります。

階層的なリソース管理:ワークスペースの中にプロジェクトがあり、その中にジョブがある、という入れ子構造になっています。それぞれの階層で細かく権限をコントロールしつつ、ユーザーから見て「なるほど」と思える継承の振る舞いも維持しないといけません。

プライベートデータでの公開公開:Re:Earthでは、データの所有権はそのままにしながら、トークン付きのリンクで安全に外部公開できる仕組みを用意しています。元になるワークスペースや認証情報、ソースデータを表に出すことなく、特定のプロジェクトの可視化だけを読み取り専用で見せるURLを発行できる、というイメージです。

セキュリティと協業機能のバランス

Re:Earthの認可設計でいちばん難しいのは、セキュリティを犠牲にせずスムーズな協業も成り立たせることです。そこから出てきた要件がいくつかあります。

ワークスペース分離:Re:Earthを使う組織は、インフラを共有していても自社のデータが他の組織に漏れないように、リソースをしっかり分離してほしいと考えています。

柔軟なチーム構造:同じワークスペースの中でも、メンバーに求められるアクセスレベルはバラバラです。データセットには自由に触れたいけれど公開済みプロジェクトは閲覧だけでいいエンジニアもいれば、その逆のメンバーもいる、というふうに。

拡大するユーザー基盤に対応する認可のスケーリング

Re:Earthのユーザーが増えるにつれて、認可システムにも一緒にスケールしてもらう必要があります。

スケールでのパフォーマンス:認可チェックはAPIリクエストやUI操作のたびに走るので、とにかく速くないと話になりません。それでいて正確さも落とせない、という条件です。

ロール管理の複雑さ:組織が大きくなると、どうしても専門的なロールを増やしたくなります。とはいえ、ロールが何百個もできて誰も把握できなくなる「ロール爆発」状態にだけは陥らないように、設計しておく必要があります。

4. なぜCerbosを選んだのか

Cerbosとは

Cerbosは、アプリケーション本体から認可ロジックを切り離せる、オープンソースのステートレスな認可サービスです。ポリシーはYAMLで書き、軽量なエンジンが評価します。サイドカー、独立したサービス、組み込みライブラリのいずれの形でも動かせるのが特徴です。ポリシーがアプリの外側にあるおかげで、認可ルールもInfrastructure as Codeと同じ感覚でレビュー・テスト・バージョン管理ができます。ソースコードはGitHubで公開されています。

認可ソリューションの評価

2024年の初めごろ、ひとつ大きな判断を迫られました。それまでのワークスペース単位のロール管理が、広がっていく製品群にもう追いつかなくなっていたのです。既存の動作はそのままに、Re:Earth FlowやVisualizerなどをまとめて面倒を見られる、中央集約型の認可サービスがどうしても欲しい状況でした。

評価では、3つの選択肢を比べました。

Open Policy Agent(OPA):機能は強力なのですが、RegoというPrologベースの構文に学習コストがそれなりにかかりますし、Goとの相性もあまり良くありませんでした。

カスタムOAuth + データベースソリューション:Auth0の上に自前のRBACを組む方法。自由度は最大ですが、ポリシー評価・キャッシュ・監査ログまわりをぜんぶ自分たちで作り直すことになり、ちょっと割に合わない感じでした。

Cerbos:もともとクラウドネイティブな認可向けに作られていて、YAMLでポリシーが書けるのでチームもすぐ読めますし、Infrastructure as Codeと一緒にバージョン管理に乗せられるのも魅力でした。

CerbosのRe:Earthに合致した主要機能

サービス非依存のリソースモデル:Re:Earthの各プロダクトは、共通のユーザー基盤とロール基盤を使いつつ、それぞれのサービス固有のリソースは自由に定義できます。

# Flow service resources
flow:project: ["read", "create", "edit", "delete"]
flow:deployment: ["read", "create", "execute", "delete"]
flow:job: ["read", "cancel", "retry"]

# Visualizer service resources  
viz:scene: ["read", "edit", "publish"]
viz:layer: ["read", "create", "edit", "delete"]

分離されたポリシー管理のメリット

ポリシーの「定義」と「適用」を分けたことで、開発の流れが大きく変わりました。

  1. 各プロダクトはサービスのコードの中でリソースとアクションを定義する
  2. CI/CDがそれらを検証・テストし、GCSにデプロイする
  3. Cerbosサイドカーがサービスを再起動せずにポリシーをホットリロードする

この構成のおかげで、既存の連携を壊さずに、サービスごとに少しずつ「ワークスペース全体のロール」から「リソース単位のきめ細かい権限」へと移行していくことができました。

統合の容易さと開発者体験

アカウントサービスが、ちょうど翻訳役のようなレイヤーとして間に入ります。

CheckPermissionメソッドが認可チェックのまとめ役です。 まずDBからユーザーのロールを読み取り、Cerbos用のプリンシパルと、リクエストされたservice/resource/actionに対応するリソースを組み立てて、Cerbosに「これってOK?」と聞きに行きます。 CerbosがALLOWを返せばAllowed: true、ロールが無い、もしくはアクションが明示的に許可されていない場合はAllowed: falseを返す、というシンプルな作りです。

ポイントは、各サービスがCerbosの存在を意識しなくていい、というところです。サービスはGraphQLで「これ許可?」と聞くだけ。ポリシー評価の細かい話はアカウントサービスが引き受けてくれます。この抽象化があるおかげで、たくさんのマイクロサービスに手を入れずとも、認可のやり方を少しずつ進化させていけます。

5. 実装の道のり

初期のアーキテクチャ決定

構成としては、Flow・Visualizer・CMSなど各サービスが自分のリソース定義を持ちつつ、認可サービスだけは共通のものを使う、というマイクロサービス的なかたちをとっています。

システムアーキテクチャ概要

認可がシステム全体をどう流れていくかは、次の図のとおりです。

リクエストフロー

  1. ユーザーがJWTトークンをヘッダーに付けて、アプリケーションサービス(Flow、Visualizerなど)にリクエストを送る
  2. アプリケーションサービスは、そのJWTヘッダーを付けたままリクエストをアカウントサービスに転送する
  3. アカウントサービス側のミドルウェアでJWTを検証し、DBからユーザー情報を取り出す
  4. アカウントサービスが、ユーザーのロール・サービス名・リソース・アクションをまとめてCerbosに問い合わせる
  5. Cerbosがポリシーを評価し、許可か拒否かを返す

主要なアーキテクチャ選択

  • 認証チェーンをつなぐためにJWTトークンはヘッダーで受け渡す
  • 認可の判断はアカウントサービスに一本化する
  • サービス間のやり取りはGraphQL
  • ポリシーファイルはGoogle Cloud Storageに置いて保存性を確保
  • ポリシーのデプロイはGitHub Actionsで自動化

Re:EarthリソースのCerbosポリシーへのマッピング

各サービスでは、リソースの一覧をコードで定義しておき、それをCerbosのポリシーファイルにコンパイルして使う、という流れにしています。

// Resource definition structure
const (
    ServiceName = "flow"

    // Resources
    ResourceProject = "project"
    ResourceDeployment = "deployment"
    ResourceJob = "job"

    // Actions
    ActionRead   = "read"
    ActionCreate = "create"
    ActionEdit   = "edit"
    ActionDelete = "delete"
)

この定義をもとに、Cerbosが評価する次のようなYAMLポリシーが生成されます。

# Generated flow_project.yaml
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  version: default
  resource: flow:project
  rules:
  - actions:
    - read
    effect: EFFECT_ALLOW
    roles:
    - reader
  - actions:
    - delete
    effect: EFFECT_ALLOW
    roles:
    - maintainer
    - owner

ロール階層の設計

ロール周りはPostgreSQLに置いてあり、階層的な権限モデルとして表現しています。

-- Database schema
Role: {id, name}
Permittable: {
    id,
    user_id,
    role_ids[]
}

ロール

  • reader
  • editor
  • maintainer
  • owner

サービスごとに「このアクションはこのロールだけOK」といった設定を独自に決められるので、柔軟な権限モデルが組めます。

複雑な権限シナリオの取り扱い

サービス固有の認可:各サービスは自分のリソース定義と権限ルールを持つので、認可モデルもそれぞれ独立して進化していけます。

// GraphQL request structure from services to Account
type checkPermissionQuery struct {
    CheckPermission struct {
        Allowed bool
    } `graphql:"checkPermission(input: {
        service: $service, // "flow", "visualizer", "cms"
        resource: $resource, // "project", "deployment", etc.
        action: $action // "read", "create", "edit", "delete"
    })"`
}

ワークスペース分離:アカウントサービスは、JWT検証で取得したユーザーデータからワークスペースのコンテキストを取り出してくれます。各サービス側でいちいち「このワークスペースに居るか?」をチェックしなくても、テナント分離がしっかり効くようになっています。

CI/CD統合:GitHub Actionsのワークフローでは、次のことが自動で走ります。

  1. Go定義からポリシーファイルを生成する(make gen-policies)
  2. その環境用のGoogle Cloud Storageにポリシーを同期する
  3. 本番デプロイ向けにポリシーをArtifact Registryへアーカイブする
  4. 更新後のポリシーでCerbos Cloud Runのデプロイを走らせる

Artifact Registryへのアーカイブがあるおかげで、本番環境では検証済みのポリシーバージョンをそのまま取りに行けて、複数のGCPプロジェクト・環境のあいだでも内容を揃えやすくなっています。

この構成だと、サービスチームごとに自分たちの認可ルールを自由に育てつつ、ポリシーの適用そのものは中央でまとめて管理できるので、柔軟さとセキュリティの両方を取れるのが嬉しいところです。

6. Re:Earthにおける実際の認可シナリオ

Re:Earthはまだ進化の途中ですが、すでに製品のいくつかの場面でCerbosベースのRBACを実運用しています。ここでは網羅的な話ではなく、いま実際に動いているシナリオに絞って紹介します。

プロジェクトレベルのアクセス制御

Re:Earthのユーザーはワークスペースに所属していて、readereditormaintainerownerといったロールを持ちます。このロールはワークスペースごとにDBに保存されています。

サービス側で認可を行いたいとき、アカウントサービスは次のように動きます。

  1. 対象のワークスペース、もしくはプロジェクトでのユーザーのロールを引っ張ってくる
  2. そのロールでCerbos用のプリンシパルを作る
  3. resourceactionのかたちでリソース情報を組み立てる
  4. 共通のCheckPermission関数を呼んで、Cerbosに「これ通していい?」と聞く

ワークスペース単位のロールは、実質「ユーザーグループ」のように振る舞います。あるワークスペースではowner、別のワークスペースではreader、というのも、ユーザーごとに権限をベタ書きせずに自然に表現できます。

公開およびURLベースの共有

Re:Earthでは、プロジェクトをURLで共有する機能も用意しています。これも認可モデルを他の部分とそろえるため、URL共有のエンドポイントもCerbos経由で判定するようにしています。

共有URL経由でリクエストが来ると、Flowサービス側では次のようにチェックします。

  • 呼び出し元がprojectAccessへアクセスできるかを確認する(例:ワークスペースでmaintainer以上)
  • トークンを使ってproject_accessレコードを引く
  • そのリンクが公開設定(IsPublic())になっているか確認する
  • 最後に対象のプロジェクトを読み込む

内部的には、ここまでの判定がRBACモデル上のprojectAccessという専用リソースで一貫して扱われています。

7. 学んだこととベストプラクティス

ポリシーテスト戦略

認可周りはアプリケーションの挙動だけに頼らず、いくつかの層でしっかりテストしています。

アカウントサーバーでは、Cerbosコンテナを実際に立ち上げてGraphQLのcheckPermissionクエリを叩く、E2Eに近いテストを用意しています。permittableが無い場合、読み取り可能なロールが付いた場合、そもそも拒否されるべきアクションを叩いた場合など、シチュエーションごとにallowedの値を確認しています。さらにCerbosインタラクター側では、リポジトリやCerbosゲートウェイをモックしたユニットテストを用意し、permittable不在・ワークスペースメンバーシップ・リポジトリエラー・最終的なALLOW/DENY結果といったケースを潰しています。

Re:Earth Flowのほうでは、ユースケースがPermissionCheckerインターフェースに依存しているので、インタラクターのテストでモックを差し込めば「権限チェックの結果に対してビジネスロジックがちゃんと従っているか」を確認できます。

パフォーマンス最適化テクニック

いまのCerbos連携で意識しているのは、「1回ごとの権限チェックをできるだけシンプルかつ予測可能に保つ」ことです。

アカウントサーバーのCheckPermissionでは、ユーザーのpermittableを1回引いて、グローバル分とワークスペース固有分のロールIDをまとめて取り、FindByIDsを1回呼んで解決します。そのうえで、コンパクトなCerbosプリンシパル(ユーザーIDとロール名のみ)と、リソース(たとえばワークスペース情報を含むIDが付いたservice:resource)を1つだけ組み立てて、対象アクションについて1回だけCerbosに問い合わせる、という流れにしています。

キャッシュやバッチングといった重めの最適化はまだ入れていませんが、ペイロードが小さく、Cerbos往復の回数も増えない設計なので、いまのワークロードには十分間に合っています。

ドキュメンテーションとポリシーの可視性

ポリシーを把握しやすく保つために、サービスごとに小さなRBACパッケージを置いて、リソース・アクション・ロールをコードで列挙しています。

たとえばFlowサービスでは、assetprojectuserworkspaceといったリソースと、readlistcreateeditdeleteanyといったアクションをrbac/definition.goにまとめています。これらのGo定義が、開発者にとってのカタログでもあり、各サービスがアカウントサーバーのcheckPermission GraphQLエンドポイントをServiceNameresourceactionを指定して叩くときの基準にもなっています。

このコードファーストのカタログがあれば、Cerbosのポリシーを直接読みに行かなくても、「誰がYに対してXできるんだっけ?」みたいな質問にすぐ答えられます。

認可システムのスケーリング

最後に、複数サービス・複数ユースケースをまたいで認可をスケールさせてみてわかったことをいくつか。

  • ポリシー定義と適用を分けておく:ダッシュボードやFlowのようなアプリケーション側は、小さなrbacパッケージ(サービス名・リソース・アクション・ロール)でRBACモデルを定義するだけにしておき、Cerbosとは直接やり取りしない。実際の問い合わせはアカウントサーバーへのcheckPermission GraphQLクエリにまとめ、アカウントサーバー側でCerbosポリシーを評価する、というかたちにすると見通しがよくなります。
  • 粗いアクションから細かいアクションへ徐々に進化させる:たとえばprojectAccessのように、まだ広めのanyアクションを使っているリソースもあります。モデル全体を一気に作り直さなくても、必要に応じてshareunsharefetchのように具体的なアクションへ少しずつ寄せていけば十分です。
  • 変更箇所を中央に寄せる:適用がアカウントサーバーに集まっているので、CerbosのポリシーやCheckPermissionの挙動を1か所いじれば、同じserviceresourceactionを参照しているすべての呼び出し側に自動で反映されます。

8. 結論:地理空間プラットフォームのための認可の再考

主要な学び

Re:Earthのような地理空間プラットフォーム向けの認可は、単に「APIをガードする」だけの話ではありません。チームがワークスペース・プロジェクト・可視化を安心して共有しながら作業でき、かつ必要に応じて外部公開もできる、というところまで支える必要があります。

いまのアプローチは、シンプルですが大事なポイントがいくつかあります。

  • 基盤としてのRBAC:認可の土台にはロールベースアクセス制御を据えています。ユーザーはワークスペースに所属し、readereditormaintainerownerといったロールを持ち、そのロールがプロジェクトや他のリソースで何をできるかを決めます。
  • 中央の認可サービス:Flowやダッシュボードなどのアプリケーション側はCerbosを直接呼びません。代わりにアカウントサーバーへcheckPermission GraphQLリクエストを投げ、そこでロールとワークスペースのコンテキストをもとに権限を判断しています。
  • サービスごとのコードファーストRBAC定義:各サービスはServiceName、リソース、アクション、ロールを宣言する小さなrbacパッケージを持ちます。これが、「このユーザーはこのリソースにこのアクションをできる?」という質問に答えるときの、開発者と認可レイヤー共通のカタログになっています。
  • 同じモデルでのURL共有:プロジェクトをURLで外部公開する機能も、同じ認可パイプラインを通します。projectAccessリソース、トークン、IsPublic()チェックを組み合わせて、URL経由のアクセスも他と一貫したかたちで扱えるようにしました。
  • 複数レベルでのテスト:境界の両側でテストを置いています。アカウントサーバー側のcheckPermissionクエリに対するGraphQLレベルのテストと、Cerbosインタラクターや権限を意識したユースケースに対するユニットテスト。これがあるので、ポリシーや配線まわりの変更を安心してロールアウトできます。

類似プロジェクトへの推奨

地理空間プラットフォームに限らず、共有ワークスペースと公開コンテンツを抱えるマルチテナント系のアプリを作っているなら、いくつかおすすめできることがあります。

  • まずはリソースとアクションに名前を付けるところから:ツール選びの前に、プロダクトにとって本当に大事なリソース(workspaceprojectassetなど)とアクション(readcreateeditdeleteanyなど)を小さく書き出してみてください。
  • 定義と適用は分ける:リソースとアクションの定義はアプリケーションに近いところに置きつつ(たとえば小さなrbacパッケージ)、適用は専用のサービスやモジュールに集めて、ポリシーエンジンとの連携はそこに閉じる、という設計が扱いやすいです。
  • ルールをハードコードせずポリシーエンジンを使う:Cerbosのようなツールを挟むと、アプリ側のコードやサービスを個別に進化させながら、認可だけは一か所で一貫して判定できます。
  • 認可周りのテストは早めに仕込むcheckPermissionエンドポイントへの軽いE2Eチェックと、変換レイヤー(ロール→プリンシパル、リソース→属性)周りのユニットテストを少し用意しておくだけでも、後々の地味なバグをかなり防げます。
  • 最初はシンプルでいい:誰も触りたがらない完璧なモデルより、誰でも理解できるシンプルで予測しやすいRBACモデルのほうが、長く付き合えます。

あなた自身のアプリケーションでRBACを始める

これから認可を再設計するチームに、ひとつおすすめできる進め方があります。

  1. 今のアクセスルールを棚卸しする:いまの仕組みがアドホックな分岐になっていたとしても構わないので、「どのユーザー(ロール)がどのリソースで何ができるはず」を一度書き出してみる。
  2. **checkPermission**ユースケースを導入する:コードベースに権限チェック用の入口を一つ作り、そこへ少しずつ判定を寄せていきます。
  3. 中央のポリシーサービスを置く:そのユースケースの裏側にCerbosのようなポリシーエンジンを置けば、ALLOW/DENYのロジックがあちこちに散らばらなくなります。
  4. サービスのRBAC定義をコードに持ってくる:サービスごとに小さなRBACパッケージを作って、checkPermission呼び出し時に参照させます。
  5. 実際の使われ方を見ながら直していく:実運用で見えてきたパターンに合わせて、広すぎたり厳しすぎたりするアクション・ルールを少しずつ整えていきます。

Re:Earthにとっては、このアプローチがあったことで、サービスを必要以上に複雑にせずに、ワークスペース・プロジェクト・URL共有にまたがる権限を一貫して扱えるようになりました。改善の余地はまだまだありますが、テストでき、説明でき、プラットフォーム全体で共有できる基盤ができた、という手応えはあります。

Japanese

Eukaryaでは様々な職種で採用を行っています!OSSにコントリビュートしていただける皆様からの応募をお待ちしております!

Eukarya 採用ページ

Eukarya is hiring for various positions! We are looking forward to your application from everyone who can contribute to OSS!

Eukarya Careers

Eukaryaは、Re:Earthと呼ばれるWebGISのSaaSの開発運営・研究開発を行っています。Web上で3Dを含むGIS(地図アプリの公開、データ管理、データ変換等)に関するあらゆる業務を完結できることを目指しています。ソースコードはほとんどOSSとしてGitHubで公開されています。

Re:Earth / ➔ Eukarya / ➔ note / ➔ GitHub

Eukarya is developing and operating a WebGIS SaaS called Re:Earth. We aim to complete all GIS-related tasks including 3D (such as publishing map applications, data management, and data conversion) on the web. Most of the source code is published on GitHub as OSS.

Re:Earth / ➔ Eukarya / ➔ Medium / ➔ GitHub