|
| 1 | +# Role-Based Access Control (RBAC) |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The GenAI IDP Accelerator implements a comprehensive Role-Based Access Control system with **server-side enforcement** at the AppSync API layer, supplemented by UI-level navigation and action controls for a clean user experience. It also supports **config-version scoping** to restrict non-admin users to specific configuration versions (use cases). |
| 6 | + |
| 7 | +## Roles |
| 8 | + |
| 9 | +Four roles are defined as Cognito User Pool groups: |
| 10 | + |
| 11 | +| Role | Cognito Group | Description | |
| 12 | +|------|--------------|-------------| |
| 13 | +| **Admin** | `Admin` | Full access to all operations including user management and pricing | |
| 14 | +| **Author** | `Author` | Read + write access to documents, configuration, tests, discovery | |
| 15 | +| **Reviewer** | `Reviewer` | HITL review operations + limited document visibility | |
| 16 | +| **Viewer** | `Viewer` | Read-only access to documents, configuration, agent chat | |
| 17 | + |
| 18 | +### Multi-Group Support |
| 19 | + |
| 20 | +Users can belong to multiple groups. Permissions are the **union** of all group permissions. For example, a user in both `Author` and `Reviewer` groups can both write documents and perform HITL reviews. |
| 21 | + |
| 22 | +## Permission Matrix |
| 23 | + |
| 24 | +``` |
| 25 | +Feature / API Admin Author Reviewer Viewer |
| 26 | +────────────────────────────────────────────────────────────────────── |
| 27 | +DOCUMENTS |
| 28 | + List documents ✅ ✅† ✅*† ✅† |
| 29 | + View document details ✅ ✅† ✅*† ✅† |
| 30 | + Upload documents ✅ ✅ ❌ ❌ |
| 31 | + Delete documents ✅ ✅ ❌ ❌ |
| 32 | + Reprocess documents ✅ ✅ ❌ ❌ |
| 33 | + Abort workflows ✅ ✅ ❌ ❌ |
| 34 | +
|
| 35 | +HITL REVIEW |
| 36 | + Claim/Release review ✅ ❌ ✅ ❌ |
| 37 | + Complete section review ✅ ❌ ✅ ❌ |
| 38 | + Skip all section reviews ✅ ❌ ✅ ❌ |
| 39 | + Process changes (edit mode) ✅ ❌ ✅ ❌ |
| 40 | +
|
| 41 | +CONFIGURATION |
| 42 | + View config versions ✅ ✅† ❌ ✅† |
| 43 | + View/Edit configuration ✅ ✅ ❌ ❌ |
| 44 | + Save as Version (new) ✅ ❌ ❌ ❌ |
| 45 | + Save as Default ✅ ❌ ❌ ❌ |
| 46 | + Delete config version ✅ ❌ ❌ ❌ |
| 47 | + Set active version ✅ ✅ ❌ ❌ |
| 48 | + Sync BDA ✅ ✅ ❌ ❌ |
| 49 | +
|
| 50 | +DISCOVERY |
| 51 | + List/run discovery jobs ✅ ✅ ❌ ❌ |
| 52 | +
|
| 53 | +AGENT CHAT & CODE EXPLORER |
| 54 | + Chat with agent ✅ ✅ ❌ ✅ |
| 55 | + Code intelligence ✅ ✅ ❌ ✅ |
| 56 | +
|
| 57 | +TEST STUDIO |
| 58 | + View/run test sets ✅ ✅ ❌ ❌ |
| 59 | + Create/delete test sets ✅ ✅ ❌ ❌ |
| 60 | +
|
| 61 | +CAPACITY PLANNING |
| 62 | + Calculate capacity ✅ ✅ ❌ ✅ |
| 63 | +
|
| 64 | +USER MANAGEMENT |
| 65 | + List all users ✅ ❌ ❌ ❌ |
| 66 | + Create/delete users ✅ ❌ ❌ ❌ |
| 67 | + Edit user scope ✅ ❌ ❌ ❌ |
| 68 | + View own profile ✅ ✅ ✅ ✅ |
| 69 | +
|
| 70 | +PRICING |
| 71 | + View pricing ✅ ✅ ❌ ✅ |
| 72 | + Edit pricing ✅ ❌ ❌ ❌ |
| 73 | +
|
| 74 | +✅* = Reviewer sees only HITL-pending docs + their own completed reviews (server-side filtered) |
| 75 | +✅† = Scoped by allowedConfigVersions if set (see Config-Version Scoping below) |
| 76 | +``` |
| 77 | + |
| 78 | +## Config-Version Scoping (Use Case Isolation) |
| 79 | + |
| 80 | +### Overview |
| 81 | + |
| 82 | +Non-admin users can optionally be assigned **allowedConfigVersions** — a list of configuration version names that restricts their view and access to only those use cases. This enables multi-tenant or multi-use-case deployments where different teams see only their relevant documents and configurations. |
| 83 | + |
| 84 | +### How It Works |
| 85 | + |
| 86 | +- **Admin users**: Always unrestricted — `allowedConfigVersions` is ignored even if set |
| 87 | +- **All other roles** (Author, Reviewer, Viewer): If `allowedConfigVersions` is set and non-empty, the user can only: |
| 88 | + - See documents processed with those config versions (server-side filtering) |
| 89 | + - See and select those config versions in all version dropdowns |
| 90 | + - View/edit configuration for those versions only |
| 91 | +- **No scope set** (empty/null): User sees all versions and documents (unrestricted) |
| 92 | + |
| 93 | +### Scope Enforcement Points |
| 94 | + |
| 95 | +| Layer | Enforcement | |
| 96 | +|-------|-------------| |
| 97 | +| **Document List** (server-side) | `listDocuments` Lambda resolver filters by `ConfigVersion` field using `allowedConfigVersions` from UsersTable | |
| 98 | +| **Config Versions List** (server-side) | `getConfigVersions` Lambda resolver filters returned versions | |
| 99 | +| **Config Version Access** (server-side) | `getConfigVersion` Lambda resolver rejects requests for out-of-scope versions | |
| 100 | +| **Version Dropdowns** (UI) | `useConfigurationVersions` hook filters versions client-side for immediate UX | |
| 101 | +| **Default Version Selection** (UI) | All version pickers auto-select the first available scoped version | |
| 102 | + |
| 103 | +### Affected UI Components |
| 104 | + |
| 105 | +All pages with config version selectors automatically respect scope: |
| 106 | + |
| 107 | +| Page | Behavior | |
| 108 | +|------|----------| |
| 109 | +| **View/Edit Configuration** | Shows only scoped versions in Versions panel; loads first scoped version | |
| 110 | +| **Upload Documents** | Version picker shows only scoped versions | |
| 111 | +| **Discovery** | Version picker shows only scoped versions | |
| 112 | +| **Test Studio** | Test runner version picker shows only scoped versions | |
| 113 | +| **Capacity Planning** | Version picker shows only scoped versions | |
| 114 | +| **Reprocess Document** | Defaults to document's current ConfigVersion (if in scope) | |
| 115 | +| **Document List** | Server-side filtered — only shows documents matching scoped versions | |
| 116 | + |
| 117 | +### Managing User Scope |
| 118 | + |
| 119 | +Admins can manage user scope via the **User Management** page: |
| 120 | + |
| 121 | +1. **Create user with scope**: When creating a new user, optionally select config versions from the multiselect |
| 122 | +2. **Edit user scope**: Click "Edit scope" on any non-Admin user row to add/remove config versions |
| 123 | +3. **Remove scope**: Clear all selections to make a user unrestricted |
| 124 | + |
| 125 | +Admin users' scope cannot be edited (they are always unrestricted). |
| 126 | + |
| 127 | +### API: `getMyProfile` |
| 128 | + |
| 129 | +All authenticated users can call `getMyProfile` to retrieve their own profile including `allowedConfigVersions`. This is used by the UI to apply client-side scope filtering immediately on page load. |
| 130 | + |
| 131 | +```graphql |
| 132 | +query GetMyProfile { |
| 133 | + getMyProfile { |
| 134 | + userId |
| 135 | + email |
| 136 | + persona |
| 137 | + allowedConfigVersions |
| 138 | + } |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +### API: `updateUser` (Admin-only) |
| 143 | + |
| 144 | +```graphql |
| 145 | +mutation UpdateUser($userId: ID!, $allowedConfigVersions: [String]) { |
| 146 | + updateUser(userId: $userId, allowedConfigVersions: $allowedConfigVersions) { |
| 147 | + userId |
| 148 | + email |
| 149 | + allowedConfigVersions |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +## Enforcement Layers |
| 155 | + |
| 156 | +### Layer 1: AppSync Schema Auth Directives (Server-Side) |
| 157 | + |
| 158 | +Every GraphQL **mutation** has `@aws_auth(cognito_groups: [...])` directives that enforce write access at the AppSync level. If a user's Cognito group is not in the allowed list, AppSync returns an **Unauthorized** error before any resolver code runs. |
| 159 | + |
| 160 | +**Key mutations and their allowed roles:** |
| 161 | + |
| 162 | +| Mutation | Allowed Roles | |
| 163 | +|----------|---------------| |
| 164 | +| `deleteConfigVersion` | Admin | |
| 165 | +| `createUser`, `updateUser`, `deleteUser` | Admin | |
| 166 | +| `updatePricing`, `restoreDefaultPricing` | Admin | |
| 167 | +| `deleteDocument`, `updateConfiguration`, `setActiveVersion` | Admin, Author | |
| 168 | +| `uploadDocument`, `reprocessDocument`, `abortWorkflow` | Admin, Author | |
| 169 | +| `startTestRun`, `addTestSet`, `deleteTests` | Admin, Author | |
| 170 | +| `syncBdaIdp`, `uploadDiscoveryDocument` | Admin, Author | |
| 171 | +| `processChanges`, `completeSectionReview`, `claimReview` | Admin, Reviewer | |
| 172 | +| `sendAgentChatMessage`, `deleteChatSession` | All authenticated users | |
| 173 | + |
| 174 | +**Important**: `@aws_auth` directives are applied to **Mutations only**, not Queries. Read access for Queries is controlled by: |
| 175 | +- **UI navigation** (which features are visible per role) |
| 176 | +- **Server-side resolver filtering** (e.g., reviewer document filtering, config-version scoping) |
| 177 | + |
| 178 | +### Layer 2: Server-Side Resolver Filtering |
| 179 | + |
| 180 | +Lambda resolvers apply additional filtering based on the caller's identity: |
| 181 | + |
| 182 | +**Document Filtering:** |
| 183 | +- **Admin**: See all documents |
| 184 | +- **Author/Viewer**: See all documents, filtered by `allowedConfigVersions` if scope is set |
| 185 | +- **Reviewer-only**: See only HITL-pending documents + their own completed reviews, plus config-version scope |
| 186 | + |
| 187 | +**Configuration Filtering:** |
| 188 | +- `getConfigVersions`: Returns only versions in user's scope (or all if unrestricted) |
| 189 | +- `getConfigVersion`: Rejects request if version is not in user's scope |
| 190 | + |
| 191 | +**User Management Filtering:** |
| 192 | +- `listUsers`: Admin sees all users; non-admin sees only their own profile |
| 193 | +- `getMyProfile`: Returns the calling user's own profile (including `allowedConfigVersions`) |
| 194 | + |
| 195 | +### Layer 3: UI Adaptation (UX Convenience) |
| 196 | + |
| 197 | +The UI adapts based on the user's role and scope: |
| 198 | +- Navigation sidebar shows only relevant features per role |
| 199 | +- Action buttons (delete, reprocess, upload, save, import) are hidden for roles that can't perform those actions |
| 200 | +- Version dropdowns are automatically filtered to show only scoped versions |
| 201 | +- The top navigation badge shows the user's role with color coding (blue=Admin, green=Author, grey=Reviewer/Viewer) |
| 202 | +- **Admin-only buttons**: "Save as Version", "Save as Default" in Configuration; Import/Restore/Save in Pricing |
| 203 | +- **Pricing page**: Shows "View Pricing" (read-only) for non-admin; "Pricing Configuration" (editable) for admin |
| 204 | + |
| 205 | +**This layer is NOT a security boundary** — it's purely for user experience. Security is enforced at Layers 1 & 2. |
| 206 | + |
| 207 | +## User Management |
| 208 | + |
| 209 | +Admins can create users with any of the four roles via the User Management page. Each user is: |
| 210 | +1. Created in DynamoDB (source of truth) |
| 211 | +2. Synced to Cognito (for authentication) |
| 212 | +3. Added to the appropriate Cognito group (for authorization) |
| 213 | +4. Optionally assigned `allowedConfigVersions` for config-version scoping |
| 214 | + |
| 215 | +### User Table Fields |
| 216 | + |
| 217 | +| Field | Description | |
| 218 | +|-------|-------------| |
| 219 | +| `userId` | Unique identifier (UUID) | |
| 220 | +| `email` | User's email address (used as Cognito username) | |
| 221 | +| `persona` | Role: Admin, Author, Reviewer, or Viewer | |
| 222 | +| `status` | User status (active) | |
| 223 | +| `allowedConfigVersions` | Optional list of config version names for scoping | |
| 224 | +| `createdAt` | Creation timestamp | |
| 225 | + |
| 226 | +## Architecture |
| 227 | + |
| 228 | +``` |
| 229 | +┌─────────────────────────────────┐ |
| 230 | +│ Browser (UI) │ Layer 3: Navigation/button hiding + scope filtering (UX only) |
| 231 | +│ useUserRole + getMyProfile │ |
| 232 | +│ useConfigurationVersions │ ← Filters versions by allowedConfigVersions |
| 233 | +└────────────┬────────────────────┘ |
| 234 | + │ GraphQL |
| 235 | +┌────────────▼────────────────────┐ |
| 236 | +│ AppSync API │ Layer 1: @aws_auth directives (DENY if wrong group) |
| 237 | +│ Schema Directives │ |
| 238 | +└────────────┬────────────────────┘ |
| 239 | + │ |
| 240 | +┌────────────▼────────────────────┐ |
| 241 | +│ Lambda Resolvers │ Layer 2: Server-side filtering |
| 242 | +│ • listDocuments: ConfigVersion │ ← Filters by allowedConfigVersions from UsersTable |
| 243 | +│ • getConfigVersions: scope │ ← Filters version list |
| 244 | +│ • getConfigVersion: scope │ ← Rejects out-of-scope access |
| 245 | +│ • listUsers: self-only │ ← Non-admin sees only own profile |
| 246 | +└────────────┬────────────────────┘ |
| 247 | + │ |
| 248 | +┌────────────▼────────────────────┐ |
| 249 | +│ DynamoDB │ |
| 250 | +│ TrackingTable (documents) │ |
| 251 | +│ ConfigurationTable (versions) │ |
| 252 | +│ UsersTable (scope data) │ |
| 253 | +└─────────────────────────────────┘ |
| 254 | +``` |
| 255 | + |
| 256 | +## Adding New Roles |
| 257 | + |
| 258 | +To add a new role: |
| 259 | +1. Add a `AWS::Cognito::UserPoolGroup` in `template.yaml` |
| 260 | +2. Add the group name to relevant `@aws_auth` directives in `schema.graphql` |
| 261 | +3. Update the `VALID_PERSONAS` dict in `src/lambda/user_management/index.py` |
| 262 | +4. Add role detection in `src/ui/src/hooks/use-user-role.ts` |
| 263 | +5. Add navigation items in `src/ui/src/components/genaiidp-layout/navigation.tsx` |
| 264 | +6. Pass the new group as an environment variable to the UserManagement Lambda |
| 265 | + |
| 266 | +## Known Limitations |
| 267 | + |
| 268 | +- **Knowledge Base queries** do not currently enforce config-version scope. KB results may include documents from out-of-scope config versions. |
| 269 | +- **Agent Companion Chat** analytics queries (Athena) do not filter by config-version scope. |
| 270 | +- **GetDocument API** (direct document access by URL) does not enforce config-version scope at the resolver level. UI navigation hides out-of-scope documents, but direct API access is not blocked. |
| 271 | +- These limitations are tracked for Phase 3 implementation. |
0 commit comments