pkg/auth/identity_filter.go
Rama main · réplica de lectura del repositorio original.
package auth
import "strings"
// Identity filtering runs wherever Radar accepts an identity it will later
// impersonate: proxy headers, OIDC login, and session cookies. The SA's
// `impersonate` grant is cluster-scoped and K8s RBAC can't restrict it to a
// prefix, so Radar enforces the constraint where it accepts identities. It
// does not constrain anyone holding the SA's token directly.
//
// Every mode rejects Kubernetes-reserved principals. Under Radar Cloud the
// control plane is the asserting party over the tunnel, so Radar additionally
// requires the Cloud identity vocabulary.
// reservedPrincipalPrefixes are Kubernetes-reserved identity namespaces an
// impersonated identity must never assert. Blocking them removes the
// worst-case escalation ceiling (system:masters, the kubelet/node identity,
// any ServiceAccount). It does NOT contain an identity source that asserts an
// ordinary user or group bound to powerful RBAC, and is deliberately not sold
// as such.
var reservedPrincipalPrefixes = []string{
"system:", // system:masters, system:authenticated, system:nodes, system:serviceaccounts, …
}
// IsReservedPrincipal reports whether a username or group falls in a reserved
// Kubernetes namespace. Matched as an exact leading prefix so Radar's own
// namespaced synthetic principals (e.g. "radar:system:alerts:…") are
// unaffected — only leading "system:" is reserved.
func IsReservedPrincipal(principal string) bool {
for _, p := range reservedPrincipalPrefixes {
if strings.HasPrefix(principal, p) {
return true
}
}
return false
}
// radarVocabularyPrefixes are the group namespaces the Radar Cloud control
// plane legitimately injects. A compromised hub can still assert an ordinary
// radar: tier, but cannot introduce identities outside the vocabulary the
// chart binds.
var radarVocabularyPrefixes = []string{"radar:", "cloud:"}
// IsRadarVocabularyGroup reports whether a group is in the Radar Cloud group
// vocabulary (radar:* canonical or cloud:* legacy).
func IsRadarVocabularyGroup(group string) bool {
for _, p := range radarVocabularyPrefixes {
if strings.HasPrefix(group, p) {
return true
}
}
return false
}
// ForwardedIdentityAllowed decides whether an identity may be impersonated. It
// enforces:
//
// - reserved-principal rejection (every mode): username and every group must
// be outside the reserved K8s namespaces (blocks system:masters etc.),
// except the group system:authenticated;
// - vocabulary allowlist (Cloud only): username must be a Cloud identity and
// every group must be radar:*/cloud:*.
//
// Returns false to reject the whole identity — never silently drops values,
// which would quietly change what the user is authorized to do.
func ForwardedIdentityAllowed(username string, groups []string, cloudMode bool) bool {
if IsReservedPrincipal(username) {
return false
}
for _, g := range groups {
// system:authenticated is the one reserved group a proxy may assert:
// every signed-in user has it, and the API server adds it to every
// impersonated user anyway.
if IsReservedPrincipal(g) && g != "system:authenticated" {
return false
}
}
if !cloudMode {
return true
}
if !isCloudUsername(username) {
return false
}
for _, g := range groups {
if !IsRadarVocabularyGroup(g) {
return false
}
}
return true
}
// isCloudUsername reports whether a username is one the Radar Cloud control
// plane legitimately injects: the opaque per-user id the hub sets as
// X-Forwarded-User, or an internal synthetic principal namespaced under
// "radar:system:" or the AI username "radar:ai:<org>". The hub never forwards
// a K8s-reserved username, so rejecting reserved is the meaningful check; the
// opaque WorkOS id has no fixed prefix to match beyond "non-empty and not reserved".
func isCloudUsername(username string) bool {
return username != "" && !IsReservedPrincipal(username)
}