Permissions refactor: tap.auth.* roles + groupMapping (#1942)

* auth: drop AUTH_ROLES; add AUTH_GROUP_MAPPING + built-in defaultRole

Companion to kubeshark/hub#permissions-refactoring. Aligns the CLI
config struct, chart values, and rendered ConfigMap with the
post-refactor hub.

config/configStructs/tapConfig.go:
  - Drop AuthConfig.Roles (admin-authored map[string]Role) and the
    Role + ScriptingPermissions structs they referenced.
  - Drop AuthConfig.DefaultFilter (no namespace scoping in v1).
  - Add AuthConfig.GroupMapping (map[string]string) — SSO group name
    → built-in role translation.
  - Tighten DefaultRole godoc to reference the four built-in role
    constants (kubeshark-admin / kubeshark-realtime /
    kubeshark-snapshot / kubeshark-viewer) and the strict-deny
    semantics on empty.

config/configStruct.go:
  - Drop the legacy "admin" entry from the AuthConfig default —
    operators now configure DefaultRole + GroupMapping instead.
  - Default RolesClaim is now "groups" (Okta/OIDC convention; was
    "role"), matching the hub's runtime default.

helm-chart/templates/12-config-map.yaml:
  - Drop AUTH_ROLES emission (key no longer read by hub).
  - Add AUTH_GROUP_MAPPING emission from tap.auth.groupMapping (JSON
    map; hub validates each value against the built-in role names at
    sync time).

helm-chart/values.yaml: regenerated from the Go config — drops the
tap.auth.roles block, adds tap.auth.groupMapping with the new
documentation header for DefaultRole.

Breaking change: deployments carrying tap.auth.roles in their values
will silently lose those role definitions. Migration is to remove the
roles: block and either (a) name their SSO groups to match the four
built-in role constants, or (b) populate tap.auth.groupMapping with
explicit translations.

* auth: set helm default role to kubeshark-viewer

Per round-2 permissions clarifications: SSO users whose claim doesn't
match any built-in role and isn't in AUTH_GROUP_MAPPING should fall
back to a read-only baseline instead of strict-deny ("").

defaultRole="" causes the dashboard to 403-storm gated endpoints from
unmatched users; viewer (snapshot:read only) gives them a sensible
read-only UX while still preventing any state change.

* auth: add tap.auth.roles operator-defined role catalogue

Chart-side companion to hub commit 67162b2e (Phase C of the permissions
refactor). Operators can now declare named roles with their own
capability set + namespace scope under tap.auth.roles; the
12-config-map renders these as AUTH_ROLES JSON for the hub to consume.

  - config/configStructs: AuthConfig.Roles map[string]RoleConfig with
    Capabilities + Namespaces; doc comments updated for groupMapping +
    defaultRole to reflect that user-defined names are now accepted.
  - config/configStruct.go: zero-value initializer for Roles so
    `kubeshark config` renders `roles: {}` consistently.
  - helm-chart/templates/12-config-map.yaml: AUTH_ROLES emits the
    full roles map as JSON; hub-side syncAuthRoles validates names
    (kubeshark-* prefix reserved) and capabilities (unknown caps
    warn-dropped).
  - helm-chart/values.yaml: regenerated. Diff is the single `roles: {}`
    line under tap.auth.

Spot-checked the rendered ConfigMap:

  AUTH_ROLES: '{"payments-viewer":{"capabilities":["snapshot:read",
                                                   "dissection:live"],
                                    "namespaces":"payments"}}'

which is exactly the shape the hub parser expects.

* auth: emit CHART_VERSION into hub ConfigMap (Phase V)

Hub commit 51abc954 reads this key on first SyncConfig and warns when
its embedded version.Ver disagrees with the chart at the major
component. Provided alongside as the chart-side companion to keep
both sides on one PR per repo on the permissions-refactoring branch.

* Revert "auth: emit CHART_VERSION into hub ConfigMap (Phase V)"

This reverts c21e4c42. Companion to hub revert 61a275b6 — the hub no
longer reads CHART_VERSION, so emitting it serves no purpose.

* chore: drop internal plan ref from auth config comment

Plans live as local working docs, not in the repo — strip the cross-repo
plans/permissions-decisions.md reference from the AuthConfig.Roles comment.
This commit is contained in:
Volodymyr Stoiko
2026-07-14 20:19:55 +03:00
committed by GitHub
parent 9396e64b9b
commit fcceed23ab
4 changed files with 44 additions and 57 deletions

View File

@@ -102,23 +102,10 @@ func CreateDefaultConfig() ConfigStruct {
}, },
}, },
Auth: configStructs.AuthConfig{ Auth: configStructs.AuthConfig{
RolesClaim: "role", RolesClaim: "groups",
Roles: map[string]configStructs.Role{ DefaultRole: "kubeshark-viewer",
"admin": { GroupMapping: map[string]string{},
Filter: "", Roles: map[string]configStructs.RoleConfig{},
CanDownloadPCAP: true,
CanUseScripting: true,
ScriptingPermissions: configStructs.ScriptingPermissions{
CanSave: true,
CanActivate: true,
CanDelete: true,
},
CanUpdateTargetedPods: true,
CanStopTrafficCapturing: true,
CanControlDissection: true,
ShowAdminConsoleLink: true,
},
},
}, },
EnabledDissectors: []string{ EnabledDissectors: []string{
"amqp", "amqp",

View File

@@ -155,23 +155,6 @@ type ProbeConfig struct {
FailureThreshold int `yaml:"failureThreshold" json:"failureThreshold" default:"3"` FailureThreshold int `yaml:"failureThreshold" json:"failureThreshold" default:"3"`
} }
type ScriptingPermissions struct {
CanSave bool `yaml:"canSave" json:"canSave" default:"true"`
CanActivate bool `yaml:"canActivate" json:"canActivate" default:"true"`
CanDelete bool `yaml:"canDelete" json:"canDelete" default:"true"`
}
type Role struct {
Filter string `yaml:"filter" json:"filter" default:""`
CanDownloadPCAP bool `yaml:"canDownloadPCAP" json:"canDownloadPCAP" default:"false"`
CanUseScripting bool `yaml:"canUseScripting" json:"canUseScripting" default:"false"`
ScriptingPermissions ScriptingPermissions `yaml:"scriptingPermissions" json:"scriptingPermissions"`
CanUpdateTargetedPods bool `yaml:"canUpdateTargetedPods" json:"canUpdateTargetedPods" default:"false"`
CanStopTrafficCapturing bool `yaml:"canStopTrafficCapturing" json:"canStopTrafficCapturing" default:"false"`
CanControlDissection bool `yaml:"canControlDissection" json:"canControlDissection" default:"false"`
ShowAdminConsoleLink bool `yaml:"showAdminConsoleLink" json:"showAdminConsoleLink" default:"false"`
}
type SamlConfig struct { type SamlConfig struct {
IdpMetadataUrl string `yaml:"idpMetadataUrl" json:"idpMetadataUrl"` IdpMetadataUrl string `yaml:"idpMetadataUrl" json:"idpMetadataUrl"`
X509crt string `yaml:"x509crt" json:"x509crt"` X509crt string `yaml:"x509crt" json:"x509crt"`
@@ -191,13 +174,41 @@ type AuthConfig struct {
// to mean Descope, switch to `descope` (or `default`). The rename is a // to mean Descope, switch to `descope` (or `default`). The rename is a
// breaking change documented in the release notes. // breaking change documented in the release notes.
Type string `yaml:"type" json:"type" default:"saml"` Type string `yaml:"type" json:"type" default:"saml"`
Roles map[string]Role `yaml:"roles" json:"roles"`
RolesClaim string `yaml:"rolesClaim" json:"rolesClaim"` RolesClaim string `yaml:"rolesClaim" json:"rolesClaim"`
// DefaultRole is applied when the authenticated user's SSO claim has no
// recognized group. Must be one of the four built-in roles
// (kubeshark-admin / kubeshark-realtime / kubeshark-snapshot /
// kubeshark-viewer), the name of an operator-defined role under
// `tap.auth.roles`, or empty for strict-deny.
DefaultRole string `yaml:"defaultRole" json:"defaultRole"` DefaultRole string `yaml:"defaultRole" json:"defaultRole"`
DefaultFilter string `yaml:"defaultFilter" json:"defaultFilter"` // GroupMapping translates SSO group names into role names (built-in or
// operator-defined). Optional — groups whose name already matches a
// built-in role are identity-matched and don't need an entry here.
// Operator-defined role names MUST appear here to participate in
// resolution (identity-match is built-in-only).
GroupMapping map[string]string `yaml:"groupMapping" json:"groupMapping"`
// Roles is the operator-defined role catalogue, keyed by role name.
// Each role has its own capability set + namespace scope. Names with
// the `kubeshark-` prefix are reserved for built-ins and will be
// rejected at hub startup. Unknown capability strings are dropped
// with a warning; empty / "*" namespace specs mean deny-all-data and
// allow-all respectively.
Roles map[string]RoleConfig `yaml:"roles" json:"roles"`
Saml SamlConfig `yaml:"saml" json:"saml"` Saml SamlConfig `yaml:"saml" json:"saml"`
} }
// RoleConfig is an operator-defined role declared under tap.auth.roles.
// Capabilities is the closed vocabulary documented in the hub project
// (snapshot:read / snapshot:write / snapshot:dissection / dissection:live /
// dissection:control / pods:target:write / settings:write); unknown
// capability strings are warn-dropped at hub startup. Namespaces is a
// comma-separated list with `*` (allow-all) and glob (`foo-*`, `*-bar`,
// `*mid*`) support; empty string means deny-all-data.
type RoleConfig struct {
Capabilities []string `yaml:"capabilities" json:"capabilities"`
Namespaces string `yaml:"namespaces" json:"namespaces"`
}
type IngressConfig struct { type IngressConfig struct {
Enabled bool `yaml:"enabled" json:"enabled" default:"false"` Enabled bool `yaml:"enabled" json:"enabled" default:"false"`
ClassName string `yaml:"className" json:"className" default:""` ClassName string `yaml:"className" json:"className" default:""`

View File

@@ -29,9 +29,10 @@ data:
{{ (default false .Values.demoModeEnabled) | ternary "default" .Values.tap.auth.type }} {{ (default false .Values.demoModeEnabled) | ternary "default" .Values.tap.auth.type }}
{{- end }}' {{- end }}'
AUTH_SAML_IDP_METADATA_URL: '{{ .Values.tap.auth.saml.idpMetadataUrl }}' AUTH_SAML_IDP_METADATA_URL: '{{ .Values.tap.auth.saml.idpMetadataUrl }}'
AUTH_ROLES: '{{ .Values.tap.auth.roles | toJson }}'
AUTH_ROLES_CLAIM: '{{ .Values.tap.auth.rolesClaim }}' AUTH_ROLES_CLAIM: '{{ .Values.tap.auth.rolesClaim }}'
AUTH_DEFAULT_ROLE: '{{ default "" .Values.tap.auth.defaultRole }}' AUTH_DEFAULT_ROLE: '{{ default "" .Values.tap.auth.defaultRole }}'
AUTH_GROUP_MAPPING: '{{ default (dict) .Values.tap.auth.groupMapping | toJson }}'
AUTH_ROLES: '{{ default (dict) .Values.tap.auth.roles | toJson }}'
AUTH_OIDC_ISSUER: '{{ default "not set" (((.Values.tap).auth).oidc).issuer }}' AUTH_OIDC_ISSUER: '{{ default "not set" (((.Values.tap).auth).oidc).issuer }}'
AUTH_OIDC_REFRESH_TOKEN_LIFETIME: '{{ default "3960h" (((.Values.tap).auth).oidc).refreshTokenLifetime }}' AUTH_OIDC_REFRESH_TOKEN_LIFETIME: '{{ default "3960h" (((.Values.tap).auth).oidc).refreshTokenLifetime }}'
AUTH_OIDC_STATE_PARAM_EXPIRY: '{{ default "10m" (((.Values.tap).auth).oidc).oauth2StateParamExpiry }}' AUTH_OIDC_STATE_PARAM_EXPIRY: '{{ default "10m" (((.Values.tap).auth).oidc).oauth2StateParamExpiry }}'

View File

@@ -153,22 +153,10 @@ tap:
auth: auth:
enabled: false enabled: false
type: saml type: saml
roles: rolesClaim: groups
admin: defaultRole: kubeshark-viewer
filter: "" groupMapping: {}
canDownloadPCAP: true roles: {}
canUseScripting: true
scriptingPermissions:
canSave: true
canActivate: true
canDelete: true
canUpdateTargetedPods: true
canStopTrafficCapturing: true
canControlDissection: true
showAdminConsoleLink: true
rolesClaim: role
defaultRole: ""
defaultFilter: ""
saml: saml:
idpMetadataUrl: "" idpMetadataUrl: ""
x509crt: "" x509crt: ""