mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-21 15:46:43 +00:00
fix: enforce the signed-in user's role on cross-node proxied requests (#1505)
Proxied requests authenticated to a remote node previously ran as admin regardless of the originating user's role, so a non-admin using the UI against a remote node could reach admin-only handlers there. The forwarding primary now asserts the user's role on a trusted header that the remote honors only for node_proxy/pilot_tunnel bearers (the same trust model as the license tier header), and the gateway overwrites the header on every proxied request so a client cannot smuggle it. An absent header keeps admin for direct instance-to-instance and background service calls; an unrecognized role fails closed to read-only.
This commit is contained in:
@@ -304,7 +304,14 @@ export interface WebhookExecution {
|
||||
|
||||
export type AuthProvider = 'local' | 'ldap' | 'oidc_google' | 'oidc_github' | 'oidc_okta' | 'oidc_custom';
|
||||
|
||||
export type UserRole = 'admin' | 'viewer' | 'deployer' | 'node-admin' | 'auditor';
|
||||
// Source of truth for the role set. UserRole derives from it so the union and
|
||||
// the runtime list cannot drift (adding a role here updates both).
|
||||
export const USER_ROLES = ['admin', 'viewer', 'deployer', 'node-admin', 'auditor'] as const;
|
||||
export type UserRole = typeof USER_ROLES[number];
|
||||
/** Narrow an untrusted string (e.g. a proxied role header) to a known UserRole. */
|
||||
export function isUserRole(value: unknown): value is UserRole {
|
||||
return typeof value === 'string' && (USER_ROLES as readonly string[]).includes(value);
|
||||
}
|
||||
export type ResourceType = 'stack' | 'node';
|
||||
|
||||
export interface User {
|
||||
|
||||
@@ -6,3 +6,13 @@
|
||||
* authenticated as a node_proxy bearer.
|
||||
*/
|
||||
export const PROXY_TIER_HEADER = 'x-sencho-tier';
|
||||
|
||||
/**
|
||||
* Carries the signed-in user's role from the forwarding primary to the remote
|
||||
* node, so the remote enforces that user's RBAC instead of treating every
|
||||
* proxied request as admin. Trusted under the same rule as PROXY_TIER_HEADER:
|
||||
* only a request authenticated as a node_proxy/pilot_tunnel bearer may set it,
|
||||
* and the gateway overwrites it on every proxied request so a browser or API
|
||||
* client cannot smuggle a role through.
|
||||
*/
|
||||
export const PROXY_ROLE_HEADER = 'x-sencho-actor-role';
|
||||
|
||||
Reference in New Issue
Block a user