This repository is a customised fork of Red Hat Developer Hub (RHDH) for developing Kuadrant Backstage plugins.
main- Our development branch with Kuadrant plugins and customisationsrhdh-upstream-main- Tracking branch for upstream RHDH main (reference only, do not commit here)pre-migration-backup- Snapshot of old plugin structure before migration (backup only)
This repository tracks three remotes:
origin- Your fork (e.g., jasonmadigan/kuadrant-backstage-plugin)upstream- Kuadrant organisation repo (Kuadrant/kuadrant-backstage-plugin)rhdh-upstream- Red Hat Developer Hub upstream (redhat-developer/rhdh)
To pull the latest changes from upstream RHDH and rebase our Kuadrant customisations:
# fetch latest from rhdh upstream
git fetch rhdh-upstream
# update the tracking branch (optional, for reference)
git checkout rhdh-upstream-main
git reset --hard rhdh-upstream/main
git push upstream rhdh-upstream-main
# rebase our main branch on top of latest rhdh
git checkout main
git rebase rhdh-upstream/main
# resolve any conflicts (see below)
# force push to update upstream after rebase
git push --force-with-lease upstream main
git push --force-with-lease origin mainWhen rebasing, you'll likely see conflicts in these files:
packages/app/src/components/AppBase/AppBase.tsx
- Conflict: Kuadrant route and Navigate import
- Resolution: Keep both upstream changes and our Kuadrant route
packages/app/src/components/catalog/EntityPage/defaultTabs.tsx
- Conflict: Kuadrant tab definitions
- Resolution: Keep our Kuadrant imports and tab configurations
packages/app/src/components/catalog/EntityPage/OverviewTabContent.tsx
- Conflict: EntityKuadrantApiAccessCard in API entity section
- Resolution: Keep our Kuadrant card addition
packages/app/src/consts.ts
- Conflict: Kuadrant menu item
- Resolution: Keep our menu item addition
packages/app/package.json
- Conflict: Kuadrant plugin dependency
- Resolution: Keep our @internal/plugin-kuadrant dependency
packages/backend/src/index.ts
- Conflict: Kuadrant backend plugin registration
- Resolution: Keep our backend.add() calls for Kuadrant plugins
app-config.local.yaml
- Conflict: Usually none (gitignored)
- Resolution: N/A
plugins/kuadrant/ # Frontend plugin
plugins/kuadrant-backend/ # Backend plugin
kuadrant-dev-setup/ # Kind cluster setup
├── crds/ # APIProduct, APIKey
├── demo/ # Toystore demo
├── rbac/ # RHDH service account
├── scripts/ # Kind cluster config
├── kuadrant-instance.yaml # Kuadrant CR
├── Makefile # Cluster setup
└── README.md
KUADRANT.md # This file
Frontend routing:
packages/app/src/components/AppBase/AppBase.tsx- Added:
import { Navigate, Route } from 'react-router-dom' - Added:
<Route path="/" element={<Navigate to="catalog" />} /> - Added:
<Route path="/kuadrant" element={<KuadrantPage />} />
- Added:
Entity page integration:
-
packages/app/src/components/catalog/EntityPage/defaultTabs.tsx- Added: Kuadrant imports
- Added:
/api-keysand/api-product-infotabs - Added: Grid wrapping for full-width layout
-
packages/app/src/components/catalog/EntityPage/OverviewTabContent.tsx- Added:
EntityKuadrantApiAccessCardfor API entities
- Added:
Navigation:
packages/app/src/consts.ts- Added: Kuadrant menu item
Dependencies:
packages/app/package.json- Added:
"@internal/plugin-kuadrant": "0.1.0"
- Added:
Backend:
packages/backend/src/index.ts- Added:
backend.add(import('@internal/plugin-kuadrant-backend')) - Added:
backend.add(import('@internal/plugin-kuadrant-backend/alpha'))
- Added:
Documentation:
CLAUDE.md- Added Kuadrant development guidance
app-config.local.yaml (checked in for dev convenience):
app:
baseUrl: http://localhost:3000
backend:
baseUrl: http://localhost:7007
cors:
origin: http://localhost:3000
credentials: true
auth:
environment: development
providers:
guest:
dangerouslyAllowOutsideDevelopment: true
catalog:
rules:
- allow: [Component, System, Group, Resource, Location, Template, API, APIProduct]# Install dependencies
yarn install
# Create kind cluster with Kuadrant
cd kuadrant-dev-setup
make kind-create
cd ..# Start RHDH with hot reload
yarn dev
# Visit http://localhost:3000
# - /kuadrant - Main plugin page
# - /catalog - Catalog with APIProduct entities
# - /catalog/default/api/toystore-api - API with Kuadrant tabsThe backend uses your local ~/.kube/config for development. Verify access:
kubectl config current-context
kubectl get apiproducts -Acd kuadrant-dev-setup
make kind-delete
make kind-createThe Kuadrant plugins ship with a comprehensive permission system for access control.
These are example role configurations - permissions are composable, so you can create custom roles mixing these permissions however you want.
API Consumer (browse all, manage own keys)
↓
API Owner (owns specific products, approves requests for own products)
↓
API Admin (owns all products, approves any request)
API Admin (platform engineer)
- Can do: View/edit ALL API Products, approve/reject any API key requests, manage RBAC policies, read PlanPolicy
- Cannot do: Create/update/delete PlanPolicy (managed on cluster by platform engineers via kubectl)
- Use case: Platform engineers who manage all API products and access control
API Owner
- Can do: Create/update OWN API Products, approve/reject requests for OWN APIs, read PlanPolicy (to reference), request API access
- Cannot do: View/edit other owners' APIs, create/update/delete PlanPolicy (managed on cluster)
- Use case: Publishes APIs they own, manages access to their own APIs
API Consumer
- Can do: Read ALL APIProducts (for catalog browsing), create APIKeys, manage own API keys
- Cannot do: Approve requests, create APIs, modify rate limits
- Use case: Browses APIs, requests access, uses APIs within quotas
The backend exports these permissions (defined in plugins/kuadrant-backend/src/permissions.ts). These appear in the RBAC plugin UI and can be composed into custom roles.
PlanPolicy (rate limit tiers):
kuadrant.planpolicy.create- create PlanPolicy resourceskuadrant.planpolicy.read- read PlanPolicy resourceskuadrant.planpolicy.update- update PlanPolicy resourceskuadrant.planpolicy.delete- delete PlanPolicy resourceskuadrant.planpolicy.list- list PlanPolicy resources
APIProduct (catalog entries with ownership):
kuadrant.apiproduct.create- create APIProduct resourceskuadrant.apiproduct.read.own- read own APIProduct resourceskuadrant.apiproduct.read.all- read all APIProduct resourceskuadrant.apiproduct.update.own- update own APIProduct resourceskuadrant.apiproduct.update.all- update any APIProduct resourcekuadrant.apiproduct.delete.own- delete own APIProduct resourceskuadrant.apiproduct.delete.all- delete any APIProduct resourcekuadrant.apiproduct.list- list APIProduct resources (backend filters by ownership)
APIKey (access requests with ownership):
kuadrant.apikey.create- create APIKey resources (resource permission scoped to APIProduct)kuadrant.apikey.read.own- read own APIKey resourceskuadrant.apikey.read.all- read all APIKey resourceskuadrant.apikey.update.own- update own APIKey resourceskuadrant.apikey.update.all- update any APIKey (approve/reject)kuadrant.apikey.delete.own- delete own APIKey resourceskuadrant.apikey.delete.all- delete any APIKey resource
Ownership Model:
APIProducts track ownership via Kubernetes annotations:
backstage.io/created-by-user-id- user ID for permission checksbackstage.io/created-by-user-ref- user entity ref for catalog owner fieldbackstage.io/created-at- creation timestamp
Backend enforces ownership checks for .own permissions:
- API Owners can only view/edit/delete their own APIProducts
- API Admins can view/edit/delete all APIProducts
- APIKey approval requires ownership of the associated APIProduct
Test users are defined in catalog-entities/kuadrant-users.yaml:
API Consumers:
consumer1(consumer1@kuadrant.local)consumer2(consumer2@kuadrant.local)
API Owners:
owner1(owner1@kuadrant.local) - API Owner 1owner2(owner2@kuadrant.local) - API Owner 2
API Admins:
admin(admin@kuadrant.local) - Administrator
Development:
guest(guest@kuadrant.local) - Guest User (member of api-owners for development convenience)
To test different permission levels, sign in as different users through your authentication provider (Dex, Keycloak, etc.)
The RBAC policy is defined in rbac-policy.csv using Casbin format. This maps:
- Roles to permissions (what each role can do)
- Groups to roles (which groups have which roles)
- Users to roles (which users have which roles)
Example policy entry:
p, role:default/platform-engineer, kuadrant.policy.write, update, allow
g, group:default/platform-engineers, role:default/platform-engineer
g, user:default/platform-engineer, role:default/platform-engineerRBAC is configured in app-config.local.yaml:
auth:
environment: development
providers:
guest:
dangerouslyAllowOutsideDevelopment: true
permission:
enabled: true
rbac:
policies-csv-file: ../../rbac-policy.csvThe RBAC policy file maps groups to roles, and users inherit permissions from their group memberships defined in the catalog.
For production deployments, the RHDH service account needs these permissions:
- Read/write access to
apiproducts.devportal.kuadrant.io - Read/write access to
apikeys.devportal.kuadrant.io - Read/write access to
secrets(for API key storage) - Read access to Kuadrant policies (optional, for policy viewing)
See kuadrant-dev-setup/rbac/rhdh-rbac.yaml for the development cluster setup.
- main is ours - This is our development repo for Kuadrant plugins
- Track upstream RHDH - Periodically rebase from rhdh-upstream to stay current with RHDH releases
- Customisations are minimal - Keep changes focused on Kuadrant integration
- Clean history - Use rebase workflow to maintain clean commit history