目次

Amazon Verified Permissions 完全ガイド v2.0

Cedar ポリシーによるアプリケーション認可ロジック外部化

Amazon Verified Permissions は、カスタムアプリケーションの認可ロジックをコードから分離し、Cedar ポリシー言語 で一元管理するフルマネージド認可サービスです。「このユーザーがこのリソースにこの操作を実行できるか」という複雑な認可判定を、コードに埋め込まず Cedar ポリシーとして外部管理。Cognito・API Gateway・AppSync・IAM Identity Center と統合し、ロール・属性・時間帯・リソース状態に基づく細粒度なアクセス制御(RBAC/ABAC)を実現します。2025-2026 年には Cedar 4.5 サポートポリシーストア別名・テンプレート機能Named Policies による参照簡素化JSON Entity Format 対応など、マルチテナント・DevOps 環境での運用が大幅に効率化された最新動向を網羅した完全リファレンスです。

ドキュメントの目的

本ガイドは以下を対象としています。

  • 初心者向け: 認可とは何か、なぜ Verified Permissions が必要かを学びたい方
  • アプリケーション開発者向け: Cedar ポリシー記述・SDK 実装・IsAuthorized API 呼び出し
  • SaaS 企業向け: マルチテナント分離・テナントセルフサービス権限管理
  • セキュリティアーキテクト向け: ABAC・ポリシー テンプレート・テストの構築
  • 意思決定者向け: Open Policy Agent・Casbin・Authzed SpiceDB・Cerbos・Auth0 FGA との比較・投資判断

2025-2026 年の Verified Permissions エコシステム

  • Cedar 4.5 サポート(2025 年 8 月): is オペレーター対応。リソースタイプベースのアクセス制御が簡素化
  • ポリシーストア別名・Named Policies(2026 年 4 月): マルチテナント開発で人間が読める名前でポリシー参照可能
  • JSON Entity Format(2025 年 2 月): Cedar SDK と同じ JSON フォーマット。開発者体験向上
  • Policy Templates: テンプレート化されたポリシーで、基本的なパターン(所有者・共有・読み取り)の実装を加速
  • CloudFormation 深化: Infrastructure as Code でポリシーストア・スキーマ・ポリシーの一括展開
  • DevOps Guru との統合: 権限使用パターン分析。未使用権限の自動検出・削除提案

概要

初心者向けメモ: 従来のアプリケーション認可は、コードに直接書く。

// アプリコードに認可ロジック埋め込み(悪い例)
if (user.role === 'admin') {
    // 管理者のみ削除可能
    deleteUser(userId);
} else if (user.role === 'manager' && user.department === userId.department) {
    // マネージャーは自分の部下のみ削除可能
    deleteUser(userId);
} else {
    throw new Error('Unauthorized');
}

// 問題点:
// - 認可ルール が複数のマイクロサービス に分散
// - ルール変更のたびにコードデプロイが必要
// - 権限監査・テストが困難

Verified Permissions は、この認可ロジックを 外部に分離

アプリケーション
    ↓ IsAuthorized API 呼び出し
    (principal, action, resource, context)
    ↓
Verified Permissions(Cedar ポリシー評価)
    ├── ポリシーストア(権限ルール管理)
    └── エンティティストア(ユーザー・リソース・グループ)
    ↓
Allow / Deny 決定を返却

Verified Permissions が実現する価値

価値 説明
認可ロジック外部化 コードから認可ロジック削除。Cedar ポリシーで一元管理
コード変更なし権限更新 ポリシー変更のみで、コードデプロイ不要
細粒度制御(ABAC) 属性(部門・プロジェクト・リソース状態)ベースのアクセス制御
マルチテナント分離 テナント ID をポリシーに組み込み。テナント間データ漏洩防止
監査・コンプライアンス ポリシーバージョン管理・アクセスログ・CloudTrail 統合
テストの自動化 Cedar ポリシーのユニットテスト・統合テスト容易

Verified Permissions が解決する課題

1. 認可ロジックの分散・保守困難性

課題:

マイクロサービス A: if (user.role == 'admin') ...
マイクロサービス B: if (user.permissions.includes('edit')) ...
マイクロサービス C: if (user.org_id == resource.org_id) ...
    ↓
認可ルールがバラバラ・重複・矛盾が発生
→ 権限監査が困難・セキュリティホール発生リスク

Verified Permissions の解決:

全マイクロサービス
    ↓ IsAuthorized API 呼び出し
Verified Permissions ポリシーストア(一元管理)
    ↓ permit / forbid ルール
Allow / Deny 決定
→ 認可ロジック一元化・変更管理が容易

2. ポリシー変更のコストが高い

課題: 「営業担当者が自分が作成した提案書のみ編集可能」というルール追加時、3 つのマイクロサービスのコード修正・テスト・デプロイが必要。リリース 1 週間。

Verified Permissions の解決:

// Cedar ポリシーとして追加(コード変更なし)
permit (
  principal == User::"sales-rep",
  action == Action::"EditProposal",
  resource.owner_id == principal.id
);

// リリース: 数分

3. テナント間データ漏洩のリスク

課題: SaaS でテナント A のユーザーがテナント B のデータにアクセス可能。テナント分離ロジックがコードに埋め込まれており、バグ修正時に誤って穴を開ける可能性。

Verified Permissions の解決:

// テナント分離をポリシーレベルで保証
permit (
  principal in Group::"tenant-a-users",
  action in [Action::"ReadData", Action::"EditData"],
  resource.tenant_id == "tenant-a"
);

forbid (
  principal == User::"*",
  resource.tenant_id != principal.tenant_id  // 他テナントアクセス禁止
);

// コードの修正バグでも、ポリシーで強制

4. 複雑な属性ベース制御(ABAC)の実装困難性

課題: 「プロジェクトマネージャーは、自分が管理するプロジェクト内の、ステータスが ‘In Progress’ のタスクのみ更新可能」という複雑なルールを実装・テストするコスト高い。

Verified Permissions の解決:

permit (
  principal in Group::"project-managers",
  action == Action::"UpdateTask",
  resource.project_id == principal.managed_project_ids,
  resource.status == "In Progress"
);

主な特徴

特徴 説明
Cedar 言語 オープンソースポリシー言語。permit / forbid で直感的に記述
Cognito 統合 Cognito ユーザー属性をポリシーで使用。ユーザー管理と認可が連動
API Gateway 統合 API Gateway オーライザーとして Verified Permissions を使用
AppSync 統合 GraphQL の @auth ディレクティブで Cedar ポリシー適用
Policy Store ポリシー・エンティティ・スキーマを一元管理
Policy Templates テンプレート化されたポリシー。基本パターンの再利用
Entity Store ユーザー・リソース・グループの属性管理
Policy Testing Cedar ポリシーのテスト。IsAuthorized API で事前検証
Version Control CloudFormation でポリシーバージョン管理
CloudTrail 統合 ポリシー変更・IsAuthorized 呼び出しを記録
Identity Source IAM Identity Center・Cognito・Custom から ユーザー・グループ同期
Schema Validation Entity データのスキーマ定義・検証。エラー防止

Cedar ポリシー言語

基本構文

// 基本形式
permit (
  principal [== / in] <principal>,
  action [== / in] <action>,
  resource [== / in] <resource>
  [when { <condition> }]
);

forbid (
  principal [== / in] <principal>,
  action [== / in] <action>,
  resource [== / in] <resource>
  [when { <condition> }]
);

実例:マルチテナント SaaS

// テナント A のユーザーのみテナント A のドキュメントを読み取り可能
permit (
  principal in Group::"tenant-a-users",
  action == Action::"ReadDocument",
  resource.tenant_id == "tenant-a"
);

// 所有者はドキュメント削除可能
permit (
  principal == User::"document-owner",
  action == Action::"DeleteDocument",
  resource.owner_id == principal.id
);

// 非営業時間のアクセスを禁止
forbid (
  principal == User::"*",
  action == Action::"AccessPremiumFeature",
  context.time_of_day < 9 || context.time_of_day > 18
);

// テナント間のアクセスを明示的に禁止
forbid (
  principal == User::"*",
  resource.tenant_id != principal.tenant_id
);

Cedar 4.5 の新機能:is オペレーター

// v4.5 から: is でリソースタイプを比較
permit (
  principal == User::"alice",
  action == Action::"Read",
  resource is Document  // resource のタイプが Document の場合
);

// 複合条件
permit (
  principal in Group::"editors",
  action == Action::"Edit",
  (resource is Document || resource is Spreadsheet)
  && resource.created_by == principal.id
);

Named Policies(2026 年 4 月)

// ポリシーに名前をつけて参照(テンプレート化)
policy "owner-can-edit" {
  permit (
    principal == User::"*",
    action == Action::"Edit",
    resource.owner_id == principal.id
  );
}

policy "admin-override" {
  permit (
    principal in Group::"admins",
    action == Action::"*",
    resource == Resource::"*"
  );
}

// ポリシーストア別名で、テナント ID を透過的に処理
// multi-tenant SaaS で { tenant_id: "customer-a" } と { tenant_id: "customer-b" } を別々に管理

アーキテクチャ

┌─────────────────────────────────────────────────────────────┐
│ アプリケーション(Express.js / Python / Node.js)        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│ req が到達
│   ↓
│ if (ユーザーが文書を編集できるか確認したい) {
│   aws verifiedpermissions.IsAuthorized({
│     policyStoreId: 'ps-...',
│     principal: { type: 'User', id: 'alice' },
│     action: { name: 'EditDocument' },
│     resource: { type: 'Document', id: 'doc-123' },
│     context: { ip: '192.168.1.1', time_of_day: 14 }
│   })
│ }
│   ↓
└───────────────────────┬───────────────────────────────────┘
                        │ IsAuthorized API 呼び出し
                        ▼
            ┌───────────────────────────┐
            │ Verified Permissions      │
            │ Policy Decision Point     │
            └───────────────┬───────────┘
                            │
                ┌───────────┴────────────┐
                ▼                        ▼
        ┌─────────────────┐    ┌──────────────────┐
        │ Policy Store    │    │ Entity Store     │
        ├─────────────────┤    ├──────────────────┤
        │ permit rules    │    │ Users            │
        │ forbid rules    │    │ Groups           │
        │ templates       │    │ Resources        │
        │ named-policies  │    │ Attributes       │
        └────────┬────────┘    └────────┬─────────┘
                 │                      │
                 │ Cedar 評価エンジン   │
                 │ (ポリシーマッチング) │
                 └──────────┬───────────┘
                            ▼
                ┌───────────────────────┐
                │ ポリシー評価結果      │
                ├───────────────────────┤
                │ DECISION: Allow       │
                │ エラー: なし          │
                └───────────────────────┘
                            │
                            ▼ API 応答
        ┌───────────────────────────────────┐
        │ アプリケーション(結果を受け取り)│
        ├───────────────────────────────────┤
        │ if (decision == Allow) {          │
        │    // 文書編集処理を実行          │
        │    editDocument(doc)              │
        │ } else {                          │
        │    // HTTP 403 Forbidden          │
        │    return forbiddenError()        │
        │ }                                 │
        └───────────────────────────────────┘

Policy Store・Schema・Entity Store

Policy Store

# Policy Store 作成(AWS CLI)
aws verifiedpermissions create-policy-store \
  --validation-settings CedarSchemaVersion=2024-08-01

# Policy Store の詳細情報取得
aws verifiedpermissions get-policy-store \
  --policy-store-id ps-examplePolicyStore

Schema(エンティティスキーマ)

{
  "cedarJson": {
    "User": {
      "type": "record",
      "attributes": {
        "id": { "type": "string" },
        "name": { "type": "string" },
        "email": { "type": "string" },
        "tenant_id": { "type": "string" },
        "department": { "type": "string" },
        "managed_projects": { "type": "set", "element": { "type": "string" } }
      }
    },
    "Document": {
      "type": "record",
      "attributes": {
        "id": { "type": "string" },
        "title": { "type": "string" },
        "tenant_id": { "type": "string" },
        "owner_id": { "type": "string" },
        "status": { "type": "string" },  // "Draft", "Approved", "Published"
        "created_by": { "type": "string" },
        "editors": { "type": "set", "element": { "type": "string" } }
      }
    },
    "Action": {
      "type": "record",
      "attributes": {}
    }
  }
}

Entity Store(エンティティデータ)

{
  "entities": [
    {
      "uid": { "type": "User", "id": "alice" },
      "attributes": {
        "id": "alice",
        "name": "Alice Smith",
        "email": "alice@company.com",
        "tenant_id": "tenant-a",
        "department": "Engineering",
        "managed_projects": ["proj-1", "proj-2"]
      },
      "parents": [
        { "type": "Group", "id": "engineers" },
        { "type": "Group", "id": "tenant-a-users" }
      ]
    },
    {
      "uid": { "type": "Document", "id": "doc-123" },
      "attributes": {
        "id": "doc-123",
        "title": "Q2 Roadmap",
        "tenant_id": "tenant-a",
        "owner_id": "alice",
        "status": "In Progress",
        "created_by": "alice",
        "editors": ["alice", "bob"]
      }
    }
  ]
}

主要ユースケース(12+)

1. マルチテナント SaaS のテナント分離

要件: SaaS プラットフォーム。テナント A のユーザーがテナント B のデータにアクセスできないよう自動分離。

実装:

// テナント A のユーザーグループ
entity TenantAUsers in { Employees } = {
  tenant_id: "tenant-a"
};

// テナント B のユーザーグループ
entity TenantBUsers in { Employees } = {
  tenant_id: "tenant-b"
};

// テナント分離ポリシー
permit (
  principal in TenantAUsers,
  action in [Action::"ReadData", Action::"EditData", Action::"DeleteData"],
  resource.tenant_id == "tenant-a"
);

forbid (
  principal in TenantAUsers,
  resource.tenant_id != "tenant-a"  // テナント A は他テナントアクセス禁止
);

// テナント B 同様
permit (
  principal in TenantBUsers,
  action in [Action::"ReadData", Action::"EditData", Action::"DeleteData"],
  resource.tenant_id == "tenant-b"
);

forbid (
  principal in TenantBUsers,
  resource.tenant_id != "tenant-b"
);

成果: コード修正なし。テナント追加時も ポリシー追加のみ。テナント間漏洩を完全に防止。

2. ドキュメント管理システムの所有者・共有者・閲覧者制御

要件: ドキュメント。所有者は編集削除可、共有者は編集可、それ以外は閲覧のみ。

実装:

// 所有者: 全操作可能
permit (
  principal == User::"*",
  action in [Action::"Read", Action::"Edit", Action::"Share", Action::"Delete"],
  resource.owner_id == principal.id
);

// 共有ユーザー: 読取・編集のみ
permit (
  principal == User::"*",
  action in [Action::"Read", Action::"Edit"],
  principal in resource.shared_users
);

// その他: 読取のみ
permit (
  principal == User::"*",
  action == Action::"Read",
  resource.is_public == true
);

// 所有者以外は削除禁止
forbid (
  principal == User::"*",
  action == Action::"Delete",
  resource.owner_id != principal.id
);

成果: 所有者・共有・閲覧の 3 段階権限。複雑な UI 設定が不要。ポリシー1つで統一制御。

3. 医療 SaaS の患者データ・医療専門職ベース制御

要件: 患者データへのアクセスは「担当医・看護師のみ」。HIPAA 準拠。

実装:

// 患者のプライマリケア医師
permit (
  principal == User::"*",
  action in [Action::"ReadPatientRecord", Action::"UpdateMedication", Action::"AddNotes"],
  resource.primary_physician_id == principal.id
);

// 患者の看護師
permit (
  principal == User::"*",
  action == Action::"ReadPatientRecord",
  principal in resource.assigned_nurses
);

// 事務員: 予約情報のみ
permit (
  principal in Group::"administrative-staff",
  action == Action::"ReadAppointmentSchedule",
  resource.type == "Patient"
);

// 医師以外はカルテ削除禁止
forbid (
  principal == User::"*",
  action == Action::"DeletePatientRecord",
  principal.role != "physician"
);

成果: 患者データ漏洩リスク 0。HIPAA 監査ログ・ポリシーバージョン管理で準拠証拠を自動生成。

4. 金融機関の融資申請承認フロー

要件: 融資申請。申請者作成 → コンプライアンスレビュー → 支店長承認 → 実行。各段階で権限が異なる。

実装:

// 申請者は自分の申請のみ確認可能
permit (
  principal == User::"*",
  action == Action::"ViewApplication",
  resource.applicant_id == principal.id
);

// コンプライアンスチーム: 全申請を確認・コメント
permit (
  principal in Group::"compliance-team",
  action in [Action::"ViewApplication", Action::"AddCompliance Comment"],
  resource.status in ["Under Review", "Approved"]
);

// 支店長: コンプライアンスOK の申請のみ承認
permit (
  principal in Group::"branch-managers",
  action == Action::"ApproveApplication",
  resource.status == "Compliance Approved"
  && resource.branch_id == principal.branch_id
);

// 一般スタッフは融資情報閲覧禁止
forbid (
  principal in Group::"general-staff",
  action in [Action::"ViewApplication", Action::"AccessLoanDetails"]
);

成果: ワークフロー状態ベースの権限自動変更。監査ログで誰がいつ何を承認したか追跡可能。

5. DevOps:ステージ・本番環境アクセス制御

要件: 開発者は dev のみ、QA 担当は staging、リリース管理者のみ prod へのアクセス。

実装:

// 開発者: dev 環境のみ
permit (
  principal in Group::"developers",
  action in [Action::"Deploy", Action::"ViewLogs", Action::"RunTests"],
  resource.environment == "dev"
);

// QA: staging のみ
permit (
  principal in Group::"qa-team",
  action in [Action::"Deploy", Action::"ViewLogs"],
  resource.environment == "staging"
);

// リリースマネージャー: prod へのアクセス(営業時間のみ)
permit (
  principal in Group::"release-managers",
  action in [Action::"Deploy"],
  resource.environment == "production"
  && context.hour >= 9
  && context.hour < 18
  && context.day_of_week != "Friday"  // 金曜日は禁止
);

// 本番環境への未承認アクセス禁止
forbid (
  principal == User::"*",
  resource.environment == "production",
  principal not in Group::"release-managers"
);

成果: 環境別・時間帯別権限。本番デプロイ事故の防止。監査要件対応。

6. テナントセルフサービス権限管理(SaaS マネージドサービス)

要件: 各テナントが自分たちのユーザー権限を管理可能。ただしテナント間の権限漏洩は防止。

実装:

// テナント管理者は自テナントのみユーザー権限を管理
permit (
  principal in Group::"tenant-admins",
  action in [Action::"ManageUsers", Action::"AssignRoles", Action::"RevokeRoles"],
  resource.tenant_id == principal.tenant_id
);

// 他テナント権限管理を禁止
forbid (
  principal in Group::"tenant-admins",
  resource.tenant_id != principal.tenant_id
);

// 全テナント管理者は自テナントの設定変更
permit (
  principal in Group::"tenant-admins",
  action == Action::"UpdateTenantSettings",
  resource.tenant_id == principal.tenant_id
);

成果: テナント各自が権限管理。SaaS 運用チームが各テナントに代わって権限設定する手間削減。

7. CI/CD パイプライン内のポリシーテスト

要件: ポリシー変更がアクセス制御を破壊しないことを本番デプロイ前に自動検証。

実装:

# Python SDK + pytest
from aws_verified_permissions import VerifiedPermissionsClient

client = VerifiedPermissionsClient()

def test_owner_can_edit_document():
    """ドキュメント所有者は編集可能"""
    response = client.is_authorized(
        policy_store_id='ps-...',
        principal={'type': 'User', 'id': 'alice'},
        action={'name': 'EditDocument'},
        resource={'type': 'Document', 'id': 'doc-123', 'owner_id': 'alice'},
    )
    assert response['decision'] == 'Allow'

def test_non_owner_cannot_delete():
    """ドキュメント非所有者は削除不可"""
    response = client.is_authorized(
        policy_store_id='ps-...',
        principal={'type': 'User', 'id': 'bob'},
        action={'name': 'DeleteDocument'},
        resource={'type': 'Document', 'id': 'doc-123', 'owner_id': 'alice'},
    )
    assert response['decision'] == 'Deny'

# CI パイプラインで自動実行
# $ pytest test_permissions.py
# 全テスト成功時のみ本番デプロイ

成果: ポリシー変更の安全性を自動検証。権限バグを本番前に検出。

8. ダイナミックデータ分類・リソース属性ベース制御

要件: ドキュメントの機密度(Public / Internal / Confidential)に基づいて、アクセス権を動的に変更。

実装:

// Public ドキュメント: 全員読み取り可能
permit (
  principal == User::"*",
  action == Action::"ReadDocument",
  resource.classification == "Public"
);

// Internal: 同一組織のみ
permit (
  principal == User::"*",
  action == Action::"ReadDocument",
  resource.classification == "Internal"
  && principal.organization_id == resource.organization_id
);

// Confidential: 文書所有者 + 承認者のみ
permit (
  principal == User::"*",
  action == Action::"ReadDocument",
  resource.classification == "Confidential"
  && (
    resource.owner_id == principal.id
    || principal in resource.approved_readers
  )
);

// 機密度が高まっても、自動的に権限剥奪(ポリシー評価時)
forbid (
  principal == User::"*",
  resource.classification == "Confidential",
  principal not in resource.approved_readers
  && principal != resource.owner_id
);

成果: リソース属性変更時、コード修正なし。自動的にアクセス権が調整。

9. グループベース・属性ベース・時間ベースの複合制御

要件: エンジニア チームの QA 環境へのアクセスは「営業時間中・QA グループメンバー・最新セキュリティパッチ適用済みデバイス」の全て。

実装:

permit (
  principal in Group::"engineers",
  action in [Action::"Deploy", Action::"ViewLogs"],
  resource.environment == "qa",
  context.is_business_hours == true,
  context.device_patch_level >= "2024-04"  // 最新セキュリティパッチ
);

forbid (
  principal == User::"*",
  resource.environment == "qa",
  context.device_patch_level < "2024-04"  // 古いデバイスはアクセス禁止
);

成果: 複雑な複合条件。コードでは書きにくい論理を Cedar で明確に表現。

10. プロジェクト・リソース所有権の動的管理

要件: ユーザーが所有するプロジェクトが変わると、自動的にアクセス権が変更される。

実装:

// ユーザーが所有するプロジェクトについては、全操作可能
permit (
  principal == User::"*",
  action in [Action::"ViewProject", Action::"EditProject", Action::"DeleteProject"],
  principal.owned_projects.contains(resource.id)
);

// ユーザーが管理するプロジェクト: 読取・編集のみ
permit (
  principal == User::"*",
  action in [Action::"ViewProject", Action::"EditProject"],
  principal.managed_projects.contains(resource.id)
);

成果: Entity Store でユーザーの owned_projects・managed_projects を更新するだけで、権限が自動的に変更。

11. API Gateway オーライザーとしての使用

要件: REST API の各エンドポイントで Verified Permissions のポリシーを適用。

実装(API Gateway オーライザー設定):

# CloudFormation で API Gateway オーライザー設定
ApiAuthorizer:
  Type: AWS::ApiGateway::Authorizer
  Properties:
    AuthorizerUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${VerifiedPermissionsAuthorizerFunction.Arn}/invocations
    AuthorizerType: TOKEN
    AuthorizerCredentials: !GetAtt AuthorizerRole.Arn
    Name: verified-permissions-authorizer

# Lambda 関数(オーライザー)
def lambda_handler(event, context):
    token = event['authorizationToken']
    user_id = extract_user_id(token)
    method = event['methodArn'].split(':')[-1].split('/')
    
    # Verified Permissions に問い合わせ
    response = verified_permissions_client.is_authorized(
        policy_store_id='ps-...',
        principal={'type': 'User', 'id': user_id},
        action={'name': 'InvokeAPI'},
        resource={'type': 'APIEndpoint', 'id': method},
    )
    
    if response['decision'] == 'Allow':
        return generate_allow_policy(user_id, event['methodArn'])
    else:
        return generate_deny_policy(user_id, event['methodArn'])

成果: API エンドポイント保護。リソース・ユーザーごとのきめ細かい制御。

12. AppSync GraphQL @auth ディレクティブ統合

要件: GraphQL Query・Mutation を Verified Permissions で保護。

実装:

# AppSync GraphQL Schema
type Query {
  getUser(id: ID!): User
    @auth(rules: [
      { allow: custom, provider: verifiedpermissions }
    ])
  
  getUserDocuments(userId: ID!): [Document]
    @auth(rules: [
      { allow: custom, provider: verifiedpermissions }
    ])
}

type Mutation {
  updateDocument(id: ID!, title: String!): Document
    @auth(rules: [
      { allow: custom, provider: verifiedpermissions }
    ])
  
  deleteUser(id: ID!): User
    @auth(rules: [
      { allow: custom, provider: verifiedpermissions }
    ])
}

VTL(Velocity Template Language)で Verified Permissions 呼び出し:

#set( $principalId = $context.identity.principalId )
#set( $resourceId = $context.arguments.id )

## IsAuthorized 呼び出し
#set( $authResponse = $context.request.authorizer.verifiedPermissions )

#if( $authResponse.decision == 'Allow' )
  ## アクセス許可
  {
    "version": "2017-02-28",
    "queryString": "{ getUser(id: \"$resourceId\") { id name email } }"
  }
#else
  ## アクセス拒否
  $utils.error("Unauthorized")
#end

成果: GraphQL API の全操作を Verified Permissions で統一制御。マイクロサービス間の複雑な権限を一元化。


設定・操作の具体例

CLI による設定例

# 1. Policy Store 作成
aws verifiedpermissions create-policy-store \
  --validation-settings CedarSchemaVersion=2024-08-01

# 出力
# {
#   "policyStoreId": "ps-examplePolicyStore"
# }

# 2. Schema 登録
aws verifiedpermissions put-schema \
  --policy-store-id ps-examplePolicyStore \
  --definition '
  {
    "cedarJson": {
      "User": {
        "type": "record",
        "attributes": {
          "id": {"type": "string"},
          "name": {"type": "string"},
          "tenant_id": {"type": "string"}
        }
      },
      "Document": {
        "type": "record",
        "attributes": {
          "id": {"type": "string"},
          "owner_id": {"type": "string"},
          "tenant_id": {"type": "string"}
        }
      },
      "Action": {"type": "record", "attributes": {}}
    }
  }'

# 3. ポリシー作成
aws verifiedpermissions create-policy \
  --policy-store-id ps-examplePolicyStore \
  --definition '
  {
    "static": {
      "description": "User can edit own documents",
      "statement": "permit (principal == User::\"alice\", action == Action::\"EditDocument\", resource.owner_id == principal.id);"
    }
  }'

# 4. Entity Store にユーザーを追加
aws verifiedpermissions create-identity-source \
  --policy-store-id ps-examplePolicyStore \
  --configuration '
  {
    "cognitoUserPoolConfiguration": {
      "userPoolArn": "arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_example"
    }
  }'

# 5. IsAuthorized API で権限判定
aws verifiedpermissions is-authorized \
  --policy-store-id ps-examplePolicyStore \
  --principal '
  {
    "entityType": "User",
    "entityId": "alice"
  }' \
  --action '
  {
    "actionType": "Action",
    "actionId": "EditDocument"
  }' \
  --resource '
  {
    "entityType": "Document",
    "entityId": "doc-123"
  }' \
  --context '{
    "contextMap": {}
  }'

SDK(Python)による設定例

import boto3
import json
from aws_verified_permissions import VerifiedPermissionsClient

# クライアント初期化
client = VerifiedPermissionsClient(region_name='us-east-1')

# 1. Policy Store 作成
response = client.create_policy_store(
    ValidationSettings={'CedarSchemaVersion': '2024-08-01'}
)
policy_store_id = response['PolicyStoreId']
print(f"Created Policy Store: {policy_store_id}")

# 2. Schema 定義
schema = {
    "cedarJson": {
        "User": {
            "type": "record",
            "attributes": {
                "id": {"type": "string"},
                "name": {"type": "string"},
                "tenant_id": {"type": "string"},
                "department": {"type": "string"}
            }
        },
        "Document": {
            "type": "record",
            "attributes": {
                "id": {"type": "string"},
                "title": {"type": "string"},
                "owner_id": {"type": "string"},
                "tenant_id": {"type": "string"},
                "status": {"type": "string"}
            }
        },
        "Action": {"type": "record", "attributes": {}}
    }
}

# Schema 登録
response = client.put_schema(
    PolicyStoreId=policy_store_id,
    Definition=json.dumps(schema)
)
print(f"Schema registered: {response['PolicyStoreId']}")

# 3. ポリシー作成(マルチテナント分離)
policy_statement = """
permit (
  principal in Group::"tenant-a-users",
  action in [Action::"ReadDocument", Action::"EditDocument"],
  resource.tenant_id == "tenant-a"
);

forbid (
  principal == User::"*",
  resource.tenant_id != principal.tenant_id
);
"""

response = client.create_policy(
    PolicyStoreId=policy_store_id,
    Definition={
        'static': {
            'description': 'Multi-tenant document access control',
            'statement': policy_statement
        }
    }
)
policy_id = response['PolicyId']
print(f"Created Policy: {policy_id}")

# 4. IsAuthorized で権限判定
def check_authorization(user_id, action, resource_id, tenant_id):
    response = client.is_authorized(
        PolicyStoreId=policy_store_id,
        Principal={
            'entityType': 'User',
            'entityId': user_id
        },
        Action={
            'actionType': 'Action',
            'actionId': action
        },
        Resource={
            'entityType': 'Document',
            'entityId': resource_id
        },
        Context={
            'contextMap': {
                'tenant_id': {'string': tenant_id}
            }
        }
    )
    return response['decision'] == 'Allow'

# テスト
alice_can_edit = check_authorization('alice', 'EditDocument', 'doc-123', 'tenant-a')
bob_can_edit = check_authorization('bob', 'EditDocument', 'doc-123', 'tenant-a')

print(f"Alice can edit: {alice_can_edit}")
print(f"Bob can edit: {bob_can_edit}")

# 5. ポリシー更新
new_policy_statement = """
permit (
  principal in Group::"tenant-a-users",
  action in [Action::"ReadDocument", Action::"EditDocument"],
  resource.tenant_id == "tenant-a"
  && context.is_business_hours == true
);
"""

response = client.update_policy(
    PolicyStoreId=policy_store_id,
    PolicyId=policy_id,
    Definition={
        'static': {
            'description': 'Multi-tenant document access (business hours only)',
            'statement': new_policy_statement
        }
    }
)
print(f"Updated Policy: {response['PolicyId']}")

IaC(CloudFormation)による設定例

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Amazon Verified Permissions Setup with CloudFormation'

Resources:
  # Policy Store
  VerifiedPermissionsPolicyStore:
    Type: AWS::VerifiedPermissions::PolicyStore
    Properties:
      ValidationSettings:
        CedarSchemaVersion: '2024-08-01'

  # Schema
  VerifiedPermissionsSchema:
    Type: AWS::VerifiedPermissions::Schema
    Properties:
      PolicyStoreId: !Ref VerifiedPermissionsPolicyStore
      Definition:
        cedarJson:
          User:
            type: record
            attributes:
              id:
                type: string
              name:
                type: string
              tenant_id:
                type: string
              department:
                type: string
          Document:
            type: record
            attributes:
              id:
                type: string
              title:
                type: string
              owner_id:
                type: string
              tenant_id:
                type: string
              status:
                type: string
          Action:
            type: record
            attributes: {}

  # Policy 1: Tenant-A Users
  TenantAPolicy:
    Type: AWS::VerifiedPermissions::Policy
    Properties:
      PolicyStoreId: !Ref VerifiedPermissionsPolicyStore
      Definition:
        static:
          description: 'Tenant A user access control'
          statement: |
            permit (
              principal in Group::"tenant-a-users",
              action in [Action::"ReadDocument", Action::"EditDocument"],
              resource.tenant_id == "tenant-a"
            );

  # Policy 2: Tenant Isolation (Forbid)
  TenantIsolationPolicy:
    Type: AWS::VerifiedPermissions::Policy
    Properties:
      PolicyStoreId: !Ref VerifiedPermissionsPolicyStore
      Definition:
        static:
          description: 'Enforce tenant isolation'
          statement: |
            forbid (
              principal == User::"*",
              resource.tenant_id != principal.tenant_id
            );

  # Identity Source (Cognito)
  CognitoIdentitySource:
    Type: AWS::VerifiedPermissions::IdentitySource
    Properties:
      PolicyStoreId: !Ref VerifiedPermissionsPolicyStore
      Configuration:
        cognitoUserPoolConfiguration:
          userPoolArn: !Sub 'arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/us-east-1_example'

Outputs:
  PolicyStoreId:
    Description: Verified Permissions Policy Store ID
    Value: !Ref VerifiedPermissionsPolicyStore
    Export:
      Name: !Sub '${AWS::StackName}-PolicyStoreId'

  PolicyStoreArn:
    Description: Verified Permissions Policy Store ARN
    Value: !GetAtt VerifiedPermissionsPolicyStore.Arn
    Export:
      Name: !Sub '${AWS::StackName}-PolicyStoreArn'

類似サービス比較表

項目 Verified Permissions Open Policy Agent Casbin Authzed SpiceDB Cerbos
言語 Cedar Rego RBAC/ABAC ZedTokens Policy DSL
マネージド ○(AWS) セルフホスト セルフホスト SaaS / Self SaaS / Self
学習曲線 低(Cedar 直感的) 中(Rego) 低(RBAC) 中(ZedTokens) 中(DSL)
RBAC
ABAC ◎◎ ◎◎
マルチテナント ◎◎
API 統合 API Gateway・AppSync 独自ホスト ライブラリ gRPC・REST gRPC・REST
テンプレート ○(v2026) × ×
テスト ○(Cedar テスト)
価格帯 AWS 従量制 無料(セルフホスト) 無料(セルフホスト) $ $
エンタープライズ対応 ×

ベストプラクティス・チェックリスト

✅ 推奨

  • [ ] 認可ロジックをコードから 完全に分離。ポリシーは Policy Store で一元管理
  • [ ] 複数環境(dev / staging / prod)でポリシーをテスト。CI/CD パイプラインに組み込み
  • [ ] マルチテナント SaaS は tenant_id を必ず resource に。テナント間漏洩を防止
  • [ ] Cedar 4.5 以上にアップグレードis オペレーター・最新機能利用
  • [ ] Named Policies・Policy Templates で再利用可能なパターン化
  • [ ] CloudFormation で IaC 管理。ポリシーバージョン管理・再現性確保
  • [ ] Identity Source 統合 で Entity 自動同期(Cognito・IAM Identity Center)
  • [ ] CloudTrail で IsAuthorized 呼び出しを記録。監査・デバッグが容易
  • [ ] Policy 変更前に必ずテスト。影響受けるユーザー・操作を事前検証

❌ アンチパターン

  • [ ] 認可ロジックがアプリコードに分散(修正・監査困難)
  • [ ] Policy Store なし(ポリシー テンプレートなし。毎回コード修正)
  • [ ] マルチテナント SaaS で tenant_id を resource に含めない(テナント分離失敗)
  • [ ] テスト不十分。ポリシー変更後に権限バグが本番で発覚
  • [ ] Policy Store が単一環境のみ(dev と prod で異なるポリシー)
  • [ ] Identity Source を使わず、Entity を手動管理(同期ズレ)
  • [ ] CloudTrail ログなし(権限変更の監査証跡がない)

2025-2026 最新動向

Cedar 4.5 サポート(2025 年 8 月)

is オペレーター により、リソースタイプベースのアクセス制御が簡素化。条件分岐が不要に。

// v4.4 (before)
if (resource.type == "Document") {
  permit(...);
}

// v4.5 (after: 'is' オペレーター)
if (resource is Document) {
  permit(...);
}

ポリシーストア別名・Named Policies(2026 年 4 月)

マルチテナント開発で、テナント ID を明示的に指定せず、別名で自動的にテナントコンテキストを処理可能。

JSON Entity Format(2025 年 2 月)

Cedar SDK と同じ JSON フォーマット対応。開発者体験向上・統一化。

Policy Templates の標準化

所有者・共有・読取といった基本パターンをテンプレート化。再利用可能・保守性向上。


学習リソース・参考文献

公式ドキュメント

パートナー・OSS リソース

AWS ブログ・セミナー


実装チェックリスト

  • [ ] アプリケーションの認可ロジック洗い出し(RBAC/ABAC パターン)
  • [ ] Cedar スキーマ設計(User / Document / Action エンティティ定義)
  • [ ] Policy Store 作成
  • [ ] Schema 登録
  • [ ] Identity Source 統合(Cognito / IAM Identity Center)
  • [ ] Cedar ポリシー作成(permit / forbid)
  • [ ] IsAuthorized API テスト(SDK / CLI)
  • [ ] Unit Test 実装(pytest / mocha)
  • [ ] API Gateway / AppSync 統合(オーライザー設定)
  • [ ] CloudFormation テンプレート作成
  • [ ] CloudTrail ログ確認
  • [ ] マルチテナント テスト(テナント分離が機能しているか)
  • [ ] ユーザーシナリオテスト(各ロールの権限動作確認)

まとめ

Amazon Verified Permissions は、アプリケーション認可ロジックをコードから分離し、Cedar ポリシーで一元管理するフルマネージドサービスです。

主な利点

  • Cedar 言語: 直感的・保守性高い
  • コード変更なし権限更新: 柔軟な権限管理
  • ABAC サポート: 属性ベースの細粒度制御
  • マルチテナント対応: テナント分離保証
  • テスト可能: ポリシー変更の安全性検証

推奨対象

  • SaaS 企業: マルチテナント分離が必須
  • マイクロサービス: 権限管理の統一化が必須
  • 金融・医療: 監査・コンプライアンス要件が厳しい

Verified Permissions は 2026 年の認可システム近代化の最優先投資対象です。Cedar 4.5・Named Policies・テンプレート機能により、エンタープライズ対応が大幅に強化。今から導入することで、認可ロジックの一元化・保守性向上・セキュリティ強化を同時に実現できます。


最終更新:2026-04-27 バージョン:v2.0