RHACS CVE Manager uses OpenShift-authenticated spoke frontends plus a hub backend. Authorization is driven by namespace annotations and group membership, not by an application-managed team table.
See Deployment for spoke setup details and User Guide for the operational workflows that sit on top of this model.
sequenceDiagram
participant User
participant OAuth as oauth-proxy
participant Injector as auth-header-injector
participant Nginx as spoke nginx
participant Hub as hub backend
User->>OAuth: Open route
OAuth->>OAuth: OpenShift OAuth login
OAuth->>Injector: Forward request<br/>X-Forwarded-User / Email / Groups / Access-Token
Injector->>Injector: Resolve namespace annotations<br/>and OpenShift groups
Injector->>Nginx: Forward request<br/>X-Forwarded-Namespaces / Namespace-Emails / Groups
Nginx->>Hub: Proxy /api/*<br/>X-Api-Key + X-Forwarded-*
Hub->>Hub: Validate API key
Hub->>Hub: Auto-provision spoke user
Hub->>Hub: Map SEC_TEAM_GROUP to sec_team
Hub-->>Nginx: API response
Nginx-->>OAuth: Response
OAuth-->>User: Response
Namespace access is derived from Kubernetes namespace annotations read by the spoke auth-header-injector.
| Annotation | Meaning |
|---|---|
rhacs-manager.io/users |
Comma-separated usernames with access to that namespace |
rhacs-manager.io/groups |
Comma-separated OpenShift groups with access to that namespace |
rhacs-manager.io/escalation-email |
Per-namespace escalation recipient |
The injector lowercases usernames and groups when building its cache. It refreshes namespace annotations every CACHE_TTL_SECONDS and caches OpenShift group lookups per access token for GROUP_CACHE_TTL_SECONDS.
When X-Forwarded-Access-Token is present, the injector calls:
/apis/user.openshift.io/v1/users/~
It reads the returned groups array and merges:
- user-based namespaces from
rhacs-manager.io/users - group-based namespaces from
rhacs-manager.io/groups
If no groups were resolved from the OpenShift user API, the injector can reuse X-Forwarded-Groups from oauth-proxy as a fallback.
The backend does not infer sec_team from namespace visibility. It uses group mapping.
| Capability | team_member |
Wildcard all-namespace user | sec_team |
|---|---|---|---|
| Read CVEs in own scope | Yes | Yes | Yes |
| Read all namespaces | No | Yes | Yes |
| Thresholds bypassed for normal list visibility | No | No | Yes |
| Create risk acceptances | Yes | Yes | No |
| Approve/reject risk acceptances | No | No | Yes |
| Create remediations | Yes | Yes | Yes |
| Verify remediations | No | No | Yes |
| Create badges | Yes | Yes | No |
| Edit settings / audit / priorities | No | No | Yes |
!!! note
Wildcard users are still team_member. They become fleet-visible because the injector emits X-Forwarded-Namespaces: *, not because the backend changes their role.
The backend materializes the authenticated user as CurrentUser with:
- persisted identity fields from the app DB
namespacesfromX-Forwarded-Namespaceshas_all_namespaceswhen the spoke sends*can_see_all_namespaceswhenis_sec_teamorhas_all_namespaces
sec_teamqueries all CVEs without threshold filtering.- Other users are limited to their namespaces and use the configured CVSS and EPSS thresholds.
- Wildcard users can query the full fleet but still use non-security-team thresholds.
sec_teamcan access all records.- Creators can always access their own records.
- Other team members can access a record when its scoped namespaces overlap their namespace set.
- Scope mode
allis visible to any user who has at least one namespace.
- Escalations are stored per
(cve_id, namespace, cluster_name, level). - Non-
sec_teamusers only see escalations in their scope. - Wildcard users can see escalations across the fleet.
- Ordinary team members list only their own badges.
- Users who can see all namespaces can list all badges.
- Badge data is scoped either to:
- an explicit namespace and cluster
- the creator's current namespace list captured at creation time
- all namespaces, but only for wildcard all-namespace users who created an unscoped badge
- Remediations are namespace-scoped and stored uniquely per
(cve_id, namespace, cluster_name). - Users need namespace access to read or update them.
- Deletion is limited to the creator or
sec_team, and only while the remediation isopenorwont_fix.
Some CVEs remain visible even if they do not meet the active thresholds.
| Condition | Always visible for non-sec_team users? |
|---|---|
| Manual priority exists | Yes |
Active risk acceptance exists (requested or approved) |
Yes |
| Below thresholds with no priority and no active risk acceptance | No |
- The hub trusts spoke requests only after constant-time
X-Api-Keyvalidation. X-Forwarded-Useris required in spoke mode.spoke:<username>is used as the stored user ID to avoid collisions with direct OIDC users.- Namespace escalation emails sent from the injector are written into the app DB so the hub can reuse them for notifications and escalations.