Self-Service CI/CD for AWS

Self-service AWS CodePipeline platform — developers ship compliant CI/CD pipelines in minutes via dashboard, CLI, CDK, or AI prompt, while platform teams enforce policy-as-code guardrails, governance, and per-team isolation.

Roles & Permissions

Access control in Pipeline Builder is permission-based and single-source. A user’s effective permissions are the union of the Roles assigned to them — there is no hidden role-derived baseline. Everything below is scoped to an organization (or team); platform-operator powers live behind the global Super Admin flag, not a per-org permission.


Overview

This reference documents Pipeline Builder’s per-org, permission-based access control: the fine-grained resource:action catalog, the built-in and custom Roles that bundle those permissions, and how they’re enforced. It’s for admins managing Roles and developers gating routes. A user’s effective permissions are the deduplicated union of their assigned Roles (a Super Admin short-circuits to all), sourced from permissions.ts and enforced by the middleware in auth.ts; a startup backfill keeps built-in Roles synced to the current catalog. Read The model first, then the permission catalog, enforcement middleware, and the API for managing Roles.


The model

Permission catalog

Category Permissions Notes
Pipelines pipelines:read, pipelines:write, pipelines:publish :publish allows setting a pipeline public
Plugins plugins:read, plugins:write, plugins:publish :publish allows setting a plugin public
Compliance compliance:read, compliance:write  
Members & access members:manage, roles:manage, invitations:manage  
Observability dashboards:read, dashboards:write, observability:read, observability:write  
Insights reports:read, reports:rollup :rollup allows including descendant teams in reports
Messaging messages:read, messages:write  
Billing & quotas billing:read, billing:manage, quotas:read  
Registry registry:read, registry:write Super Admin only — never grantable to a custom Role
Org settings org:settings General org settings + AI provider config
SSO / IdP org:idp Per-org SSO/IdP (OIDC) configuration — sensitive (controls login); split out of org:settings
KMS org:kms Customer-managed KMS key configuration — sensitive (controls encryption); split out of org:settings

:read permissions are enforced. Withholding quotas:read / reports:read / billing:read / messages:read from a custom Role actually blocks that read (backend routes and the frontend nav/page guards check it). Built-in Admin and Member both include all reads, so only bespoke custom Roles that drop a read are affected.

Registry carve-out. registry:read / registry:write are in SUPERADMIN_ONLY_PERMISSIONS: they’re in no built-in Role bundle and can’t be requested by a custom Role (sanitizePermissions strips them), so the only holder is a Super Admin via implicit-all.

Built-in Role bundles

Enforcement

Routes gate writes with permission middleware; a denied state-changing request also emits an authz.denied audit event.

Not the same as the mesh. This page covers application authorization — per-org capability checks on API routes. Beneath it, the Istio ambient service mesh enforces network authorization (L4, by service identity): which services may reach which services at all. A request must pass both — the mesh AuthorizationPolicy (can sa/pipeline reach platform:3000?) and then requirePermission (does this user hold the capability?). Don’t conflate a mesh 403 (identity not allow-listed) with an app 403 (missing permission).

Middleware Semantics
requirePermission(a, b, …) passes if the caller holds any of the listed permissions (Super Admin passes via implicit-all)
requireAllPermissions(a, b, …) passes only if the caller holds all listed permissions
requirePermissionOrService(a, …) like requirePermission, but ALSO admits an internal service:* principal — used on READ routes that both users and service-to-service callers hit (a service token carries no permission claims and would otherwise be wrongly denied)

Public-visibility is permission-based too: resolveAccessModifier grants public only to a caller holding the resource’s :publish permission — so a custom Role can be granted publish rights instead of being forced private by its coarse label. Downward report roll-up (?includeDescendants) requires reports:rollup.

Session invalidation

Access tokens are short-lived (15 min) and carry a tokenVersion. On any privilege change (role edit, permission change, superadmin grant/revoke), platform bumps the user’s tokenVersion and publishes it to a Redis-backed revocation store; requireAuth rejects a token whose version is behind (fail-open if Redis is unavailable — auth then degrades to natural token expiry, never a lockout).

Managing Roles via the API

GET|POST    /api/organization/:id/roles                       # list / create Roles
PUT|DELETE  /api/organization/:id/roles/:roleId               # update / delete a custom Role
POST|DELETE /api/organization/:id/roles/:roleId/members/:uid  # add / remove a Role member

POST / PUT / DELETE require roles:manage. Custom-Role authoring validates the requested permissions against the org-assignable set (the registry carve-out is rejected) and against the author’s own permissions (the permission ceiling above) — a request granting a permission the author lacks is rejected 403.

Teams

A parent-org admin/owner can administer its teams (members, rules, quotas) without a separate membership — fine-grained delegation applies within the team’s own tenancy boundary, and team-local Roles still bind. See Org → Team Hierarchy.