Security Model¶
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.
Authentication Flow¶
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
RBAC Source of Truth¶
Namespace access is derived from Kubernetes namespace annotations read by the spoke auth-header-injector.
Annotation Sources¶
| 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.
How Groups Are Resolved¶
When X-Forwarded-Access-Token is present, the injector calls:
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.
Role Hierarchy¶
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.
Data Scoping¶
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
CVEs¶
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.
Risk acceptances¶
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¶
- 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.
Badges¶
- 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¶
- 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.
Threshold Bypass Rules¶
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 |
Spoke-to-Hub Trust Boundary¶
- 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.