ロール・権限定義書とは

ロール・権限定義書は、RBAC(Role-Based Access Control: ロールベースアクセス制御)の設計を具体化した文書です。「誰が(アクター)」「どの機能に対して(機能)」「何ができるか(CRUD権限)」を定義し、機能設計書・画面設計書のアクセス制御実装の基準として使用します。

💡 RBAC vs ABAC vs PBAC

アクセス制御モデルには RBAC(役割ベース)・ABAC(属性ベース)・PBAC(ポリシーベース)があります。多くの業務システムでは RBAC が最も実装しやすく管理しやすい選択です。ただし「所属部署のデータのみ閲覧可」のようなデータスコープ制御は、RBAC にテナント制御・オーナーシップチェックを組み合わせて実装します。

① アクター(ユーザー種別)の定義

システムを利用するすべての人物の種別(アクター)を定義します。

アクターIDアクター名概要・特性想定人数認証方式
ACT-01システム管理者システム全体を管理。ユーザー管理・システム設定・マスタ管理すべての権限を持つ。人数は最小限に制限2〜3名パスワード + MFA(必須)
ACT-02業務管理者各業務ドメイン(営業・仕入・在庫)のデータ管理権限を持つ。部門マネージャー相当5〜10名パスワード + MFA(任意)
ACT-03一般ユーザー(営業)受注・見積の作成・更新が可能。自部門のデータのみ参照可能50〜80名パスワード(SSO連携)
ACT-04一般ユーザー(仕入)発注・仕入の作成・更新が可能。自部門のデータのみ参照可能10〜20名パスワード(SSO連携)
ACT-05閲覧専用全データを参照のみ。データ変更不可。レポート・帳票出力は可20〜30名パスワード(SSO連携)
ACT-06外部パートナー発注書・納品書のみ参照可能。自社に関するデータのみアクセス可能〜100社パスワード(招待メール)
ACT-07システム(バッチ)夜間バッチ処理用のサービスアカウント。画面は使用しないサービスアカウントトークン

② ロール定義とロール階層

アクターに割り当てるロールを定義します。1人のユーザーに複数ロールを付与できる設計にします。

ロールIDロール名ロールコード説明
ROL-01システム管理者ROLE_SYS_ADMINすべての機能・データへのフルアクセス。ユーザー管理・システム設定を含む
ROL-02業務管理者ROLE_BIZ_ADMINマスタ管理・全業務データへのCRUD。ユーザー管理・システム設定は不可
ROL-03営業担当ROLE_SALES受注・見積・顧客情報のCRUD。自部門データのみ操作可能
ROL-04仕入担当ROLE_PURCHASE発注・仕入・在庫のCRUD。自部門データのみ操作可能
ROL-05在庫担当ROLE_INVENTORY在庫・入出庫データのCRUD。他部門データは参照のみ
ROL-06閲覧専用ROLE_VIEWER全データ参照のみ。帳票・レポート出力可。データ変更不可
ROL-07外部パートナーROLE_PARTNER発注書・納品書の参照のみ。自社に関するデータのみアクセス可能

③ 権限マトリクス(機能×ロール)

各機能に対して各ロールが持つCRUD権限を一覧化します。C=作成 / R=参照 / U=更新 / D=削除 / ×=権限なし

機能カテゴリ / 機能名SYS_ADMINBIZ_ADMINSALESPURCHASEINVENTORYVIEWERPARTNER
ユーザー管理 / ユーザー一覧・検索CRUDR×××××
ユーザー管理 / ユーザー作成・編集CRUD××××××
受注管理 / 受注一覧・検索CRUDCRUDCR(自部門)RRR×
受注管理 / 受注登録・編集CRUDCRUDCRU(自部門)××××
発注管理 / 発注一覧・検索CRUDCRUDRCRUDRRR(自社分)
発注管理 / 発注登録・編集CRUDCRUD×CRU×××
在庫管理 / 在庫一覧CRUDCRUDRRCRUDR×
マスタ管理 / 商品マスタCRUDCRUDRRRR×
マスタ管理 / 取引先マスタCRUDCRUDRR×R×
帳票出力 / 受注帳票・見積書○(自部門)×××
帳票出力 / 発注書・納品書×○(自社分)
システム設定 / 全設定CRUD××××××

④ データスコープ制御

同じロールのユーザー間でも、アクセスできるデータの範囲(スコープ)を制御する設計です。

スコープ種別対象ロール実装方針
部門スコープSALES / PURCHASE / INVENTORYユーザーが所属する部門IDに紐づくデータのみ取得。全APIでWHERE句にdepartment_id = {user.department_id}を付与
全社スコープSYS_ADMIN / BIZ_ADMIN / VIEWER部門制限なし。全データにアクセス可能
取引先スコープPARTNER自社(取引先)に関するデータのみ取得。全APIでWHERE句にpartner_id = {user.partner_id}を付与

⑤ 承認フロー設計

金額・リスクの高い操作には承認フロー(申請→承認→実行)を設計します。

対象操作申請者承認者承認条件
受注登録(100万円以上)SALESBIZ_ADMIN(営業管理者)BIZ_ADMIN 1名の承認で実行可能
発注登録(50万円以上)PURCHASEBIZ_ADMIN(仕入管理者)BIZ_ADMIN 1名の承認で実行可能
マスタ削除(全件)BIZ_ADMINSYS_ADMINSYS_ADMIN 1名の承認で実行可能
ユーザー削除SYS_ADMIN別のSYS_ADMIN本人以外のSYS_ADMIN 1名の承認が必要(二重チェック)

⑥ ロール管理運用ルール

  • 最小権限の原則: 業務上必要な権限のみを付与する。デフォルトロールは VIEWER(閲覧専用)とし、追加権限は申請・承認を経て付与
  • 定期棚卸し: 四半期に1回、ロール割り当て一覧をシステム管理者がレビューし、不要な権限を削除
  • 退職・異動時の対応: 退職日(または異動日)当日にシステム管理者がアカウント無効化およびロール削除を実施。人事システムとの連携自動化を推奨
  • SYS_ADMINの最小人数制限: SYS_ADMINは2〜3名に厳格に制限。増員には上長の承認が必要

Python Tips — DjangoのRBAC設定を自動検証するスクリプト

Python — Django権限設定の自動検証
"""
DjangoのグループとパーミッションのDB設定が権限マトリクスの定義通りか検証するスクリプト。
python manage.py shell で実行するか、management commandとして組み込む。

権限マトリクスをYAMLで管理し、実際のDB設定と突合する。
"""
import yaml
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from dataclasses import dataclass


# 権限マトリクスのYAML定義例
PERMISSION_MATRIX_YAML = """
ROLE_SALES:
  order:    [view, add, change]        # 受注: 参照・作成・更新(削除不可)
  product:  [view]                     # 商品マスタ: 参照のみ
  customer: [view, add, change]        # 顧客: 参照・作成・更新

ROLE_BIZ_ADMIN:
  order:    [view, add, change, delete]
  product:  [view, add, change, delete]
  customer: [view, add, change, delete]
  purchase: [view, add, change, delete]

ROLE_VIEWER:
  order:    [view]
  product:  [view]
  customer: [view]
  purchase: [view]
"""


@dataclass
class ValidationError:
    role: str
    model: str
    permission: str
    error_type: str  # "MISSING" | "EXTRA"


def get_current_permissions(group_name: str) -> dict[str, set[str]]:
    """DBから現在のグループのパーミッション設定を取得する"""
    try:
        group = Group.objects.get(name=group_name)
    except Group.DoesNotExist:
        return {}

    result = {}
    for perm in group.permissions.select_related("content_type").all():
        model = perm.content_type.model
        # "view_order" → "view" に変換
        action = perm.codename.replace(f"_{model}", "")
        result.setdefault(model, set()).add(action)
    return result


def validate_permissions() -> list[ValidationError]:
    """権限マトリクスYAMLとDB設定を突合して差異を検出する"""
    matrix = yaml.safe_load(PERMISSION_MATRIX_YAML)
    errors = []

    for role_name, model_permissions in matrix.items():
        current = get_current_permissions(role_name)

        for model, expected_actions in model_permissions.items():
            expected_set = set(expected_actions)
            actual_set = current.get(model, set())

            # 定義されているが設定されていない権限
            for missing in expected_set - actual_set:
                errors.append(ValidationError(
                    role=role_name, model=model,
                    permission=missing, error_type="MISSING"
                ))

            # 設定されているが定義されていない権限(過剰権限)
            for extra in actual_set - expected_set:
                errors.append(ValidationError(
                    role=role_name, model=model,
                    permission=extra, error_type="EXTRA"
                ))

    return errors


def apply_permissions(dry_run: bool = True) -> None:
    """権限マトリクスYAMLに基づいてDjangoグループとパーミッションを設定する"""
    matrix = yaml.safe_load(PERMISSION_MATRIX_YAML)

    for role_name, model_permissions in matrix.items():
        group, created = Group.objects.get_or_create(name=role_name)
        action = "作成" if created else "更新"

        target_perms = set()
        for model_name, actions in model_permissions.items():
            try:
                ct = ContentType.objects.get(model=model_name)
                for act in actions:
                    codename = f"{act}_{model_name}"
                    perm = Permission.objects.get(content_type=ct, codename=codename)
                    target_perms.add(perm)
            except (ContentType.DoesNotExist, Permission.DoesNotExist) as e:
                print(f"  ⚠️ 権限が見つかりません: {model_name}.{act} — {e}")

        if dry_run:
            print(f"[DRY RUN] {action}: {role_name} ({len(target_perms)}件の権限)")
        else:
            group.permissions.set(target_perms)
            print(f"✅ {action}: {role_name} ({len(target_perms)}件の権限を設定)")


if __name__ == "__main__":
    print("=== 権限設定バリデーション ===")
    errors = validate_permissions()
    if not errors:
        print("✅ すべての権限設定が権限マトリクス通りです")
    else:
        for e in errors:
            mark = "❌ 不足" if e.error_type == "MISSING" else "⚠️ 過剰"
            print(f"  {mark}: {e.role} / {e.model} / {e.permission}")

    print("\n=== 権限設定の適用(dry run)===")
    apply_permissions(dry_run=True)

権限設定のCI/CDへの組み込み

このバリデーションスクリプトをCIパイプラインに組み込み、DjangoのGroupPermission設定が権限マトリクスYAMLから乖離していないかを自動検証できます。権限マトリクスはYAMLで管理してGitでバージョン管理し、PRレビューで権限変更の意図を確認する運用が理想的です。