mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-09-01 00:57:17 +00:00
🔒 apply tap.auth.defaultRole when authentication is disabled
An ungated deployment had no authorization at all: every caller was admin, and the only way to restrict anyone was to stand up an identity provider. So a read-only dashboard needed a login it had no use for. defaultRole now answers 'what may an unidentified caller do' as well as 'what may an authenticated caller with no recognized group do'. Setting it to kubeshark-viewer gives a read-only deployment with no login and no auth backend. Its default becomes kubeshark-admin, so an ungated install behaves as it always has, and the hub falls back to admin when the value is unset or unrecognized rather than to strict-deny — nobody configuring a role must not brick an install. Adds install-notes coverage, since the notes are where an operator learns which of the two ungated postures they got, and fills the remaining gaps in the auth suites: dex and descope validation, incomplete settings while auth is off, and worker token projection under licensing and demo mode.
This commit is contained in:
@@ -175,12 +175,17 @@ type AuthConfig struct {
|
||||
// breaking change documented in the release notes.
|
||||
Type string `yaml:"type" json:"type" default:"saml"`
|
||||
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 is applied when a caller has no recognized group, and also
|
||||
// when Enabled is false — with no authentication there is no identity,
|
||||
// but there is still a question of what an unidentified caller may do.
|
||||
// Must be one of the four built-in roles (kubeshark-admin /
|
||||
// kubeshark-realtime / kubeshark-snapshot / kubeshark-viewer) or the name
|
||||
// of an operator-defined role under `tap.auth.roles`.
|
||||
//
|
||||
// With Enabled true, empty means strict-deny. With Enabled false, empty
|
||||
// or unrecognized falls back to kubeshark-admin so an install that never
|
||||
// configured authorization keeps working.
|
||||
DefaultRole string `yaml:"defaultRole" json:"defaultRole" default:"kubeshark-admin"`
|
||||
// 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.
|
||||
|
||||
@@ -211,12 +211,12 @@ Example for overriding image names:
|
||||
| `tap.tolerations.workers` | Tolerations for workers components | `[ {"operator": "Exists", "effect": "NoExecute"}` |
|
||||
| `tap.tolerations.hub` | Tolerations for hub component | `[]` |
|
||||
| `tap.tolerations.front` | Tolerations for front-end component | `[]` |
|
||||
| `tap.auth.enabled` | Enable authentication | `false` |
|
||||
| `tap.auth.enabled` | Enable authentication. When `false` the Hub identifies nobody, but `tap.auth.defaultRole` is still applied and enforced, so a deployment can be read-only without configuring an identity provider. | `false` |
|
||||
| `tap.auth.type` | Authentication backend. Valid values: `saml`, `oidc` (generic OIDC — Dex, Okta, Auth0, Keycloak, Azure AD, Google, …), `dex` (permanent alias of `oidc`), `descope`, `default` (also routes to Descope). **Breaking**: prior releases routed `oidc` to Descope — if you were using it for Descope, switch to `descope` or `default`. | `saml` |
|
||||
| `tap.auth.approvedEmails` | List of approved email addresses for authentication | `[]` |
|
||||
| `tap.auth.approvedDomains` | List of approved email domains for authentication | `[]` |
|
||||
| `tap.auth.rolesClaim` | Name of the JWT claim (OIDC) or SAML attribute carrying role memberships. | `role` |
|
||||
| `tap.auth.defaultRole` | Optional role name inside `tap.auth.roles` applied as fallback when an authenticated user has no matching role. Empty string = no fallback, zero-valued permissions. | `""` |
|
||||
| `tap.auth.defaultRole` | Role applied when a caller has no matching role. Respected whether or not `tap.auth.enabled` is set: with authentication off it is the role every caller gets, so `kubeshark-viewer` yields a read-only deployment with no login. One of the built-in roles (`kubeshark-admin`, `kubeshark-realtime`, `kubeshark-snapshot`, `kubeshark-viewer`) or a role name from `tap.auth.roles`. With authentication on, an empty string means no fallback and therefore no permissions; with it off, an empty or unrecognized value falls back to `kubeshark-admin` so an install that never configured authorization keeps working. | `kubeshark-admin` |
|
||||
| `tap.auth.roles` | Backend-neutral role map shared by SAML and OIDC. Each role's `namespaces` is a comma-separated list controlling which Kubernetes namespaces the role's users see traffic for: `""` = deny all, `"*"` = allow all, `"foo"` = literal namespace, `"foo,bar"` = OR over literals, `"foo-*"` = glob expansion against the cluster's known namespaces. Empty/unset `tap.auth.roles` grants nothing — admins opt into elevated access by populating this map. | `{"admin":{"namespaces":"*","canDownloadPCAP":true,"canUpdateTargetedPods":true,"canUseScripting":true,"scriptingPermissions":{"canSave":true,"canActivate":true,"canDelete":true},"canStopTrafficCapturing":true,"canControlDissection":true,"showAdminConsoleLink":true}}` |
|
||||
| `tap.auth.cli.enabled` | Enable ServiceAccount-token auth for the CLI. Creates a `kubeshark-cli` ServiceAccount plus a Role permitting `create` on its token, and allowlists it on the hub via `AUTH_CLI_SERVICE_ACCOUNTS`. The CLI mints a short-lived token for that SA to authenticate to a gated hub. Map `kubeshark-cli` to a role via `tap.auth.groupMapping`; without a mapping it falls back to `tap.auth.defaultRole`. | `false` |
|
||||
| `tap.auth.cli.subjects` | RBAC subjects permitted to mint the `kubeshark-cli` token — i.e. who may use the CLI against a gated hub. Each entry mirrors an `rbacv1.Subject`: `kind` (`User`, `Group` or `ServiceAccount`), `name`, `apiGroup` (`rbac.authorization.k8s.io` for `User`/`Group`, omitted for `ServiceAccount`) and `namespace` (`ServiceAccount` only). Empty means the Role is created but bound to nobody. | `[]` |
|
||||
|
||||
@@ -26,9 +26,15 @@ Your deployment has been successful. The release is named `{{ .Release.Name }}`
|
||||
Notices:
|
||||
{{- if not .Values.tap.auth.enabled }}
|
||||
- API AUTHENTICATION IS DISABLED (tap.auth.enabled=false, the default).
|
||||
- Callers are not identified, and every one of them gets the role
|
||||
`{{ default "kubeshark-admin" .Values.tap.auth.defaultRole }}`.
|
||||
{{- if not (eq (default "kubeshark-admin" .Values.tap.auth.defaultRole) "kubeshark-admin") }}
|
||||
- That role is enforced, so anyone reaching the Hub is limited to it.
|
||||
{{- else }}
|
||||
- Anyone able to reach the Hub can read captured traffic and change settings.
|
||||
- Enable it with `--set tap.auth.enabled=true` plus a `tap.auth.type` of `saml` or `oidc`,
|
||||
and assign roles via `tap.auth.defaultRole` / `tap.auth.groupMapping`.
|
||||
- For a read-only deployment with no login, set `tap.auth.defaultRole=kubeshark-viewer`.
|
||||
{{- end }}
|
||||
- To identify callers, set `tap.auth.enabled=true` with a `tap.auth.type` of `saml` or `oidc`.
|
||||
- See https://docs.kubeshark.com/en/roles
|
||||
{{- else }}
|
||||
- API authentication is enabled (tap.auth.type={{ .Values.tap.auth.type }}).
|
||||
|
||||
@@ -116,6 +116,32 @@ tests:
|
||||
path: data.AUTH_TYPE
|
||||
value: descope
|
||||
|
||||
## AUTH_DEFAULT_ROLE decides what a caller with no recognized group may do,
|
||||
## including a caller on a deployment with no authentication at all. Its
|
||||
## default is admin, so an ungated install behaves as it always has; a
|
||||
## narrower value yields a read-only deployment with no identity provider
|
||||
## and no login.
|
||||
|
||||
- it: defaults to admin, so an ungated install is unrestricted
|
||||
asserts:
|
||||
- equal:
|
||||
path: data.AUTH_ENABLED
|
||||
value: "false"
|
||||
- equal:
|
||||
path: data.AUTH_DEFAULT_ROLE
|
||||
value: kubeshark-admin
|
||||
|
||||
- it: carries a narrowed default role with auth off
|
||||
set:
|
||||
tap.auth.defaultRole: kubeshark-viewer
|
||||
asserts:
|
||||
- equal:
|
||||
path: data.AUTH_ENABLED
|
||||
value: "false"
|
||||
- equal:
|
||||
path: data.AUTH_DEFAULT_ROLE
|
||||
value: kubeshark-viewer
|
||||
|
||||
## Role resolution inputs reach the Hub untouched, so `defaultRole` means
|
||||
## what it says for every auth type.
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
## The install notes are where an operator learns what their auth settings
|
||||
## actually did. A deployment can now be ungated, or read-only with no login
|
||||
## at all, and the difference must be stated rather than inferred.
|
||||
suite: auth install notes
|
||||
templates:
|
||||
- templates/NOTES.txt
|
||||
tests:
|
||||
- it: warns that a default install is open to anyone who can reach the Hub
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: API AUTHENTICATION IS DISABLED
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: every one of them gets the role\n `kubeshark-admin`
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: Anyone able to reach the Hub can read captured traffic
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: set `tap\.auth\.defaultRole=kubeshark-viewer`
|
||||
|
||||
# A narrowed default role is enforced, so the notes must not repeat the
|
||||
# "anyone can change settings" warning that applies to the admin default.
|
||||
- it: reports a narrowed default role as enforced
|
||||
set:
|
||||
tap.auth.defaultRole: kubeshark-viewer
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: every one of them gets the role\n `kubeshark-viewer`
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: That role is enforced
|
||||
- notMatchRegex:
|
||||
path: raw
|
||||
pattern: Anyone able to reach the Hub can read captured traffic
|
||||
|
||||
- it: reports the configured backend when authentication is on
|
||||
set:
|
||||
tap.auth.enabled: true
|
||||
tap.auth.type: oidc
|
||||
tap.auth.oidc.issuer: https://issuer.example.com
|
||||
tap.auth.defaultRole: kubeshark-viewer
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: API authentication is enabled \(tap\.auth\.type=oidc\)
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: resolve to `kubeshark-viewer`
|
||||
- notMatchRegex:
|
||||
path: raw
|
||||
pattern: API AUTHENTICATION IS DISABLED
|
||||
|
||||
# Empty defaultRole means strict-deny once callers are identified, and the
|
||||
# notes should say so rather than naming a role nobody configured.
|
||||
- it: reports deny-all when authentication is on with no default role
|
||||
set:
|
||||
tap.auth.enabled: true
|
||||
tap.auth.type: descope
|
||||
tap.auth.defaultRole: ""
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: raw
|
||||
pattern: resolve to `no role, deny-all`
|
||||
@@ -42,6 +42,34 @@ tests:
|
||||
path: data.AUTH_TYPE
|
||||
value: oidc
|
||||
|
||||
# Descope carries its own configuration, so there is nothing to require.
|
||||
- it: accepts descope without extra settings
|
||||
set:
|
||||
tap.auth.enabled: true
|
||||
tap.auth.type: descope
|
||||
asserts:
|
||||
- equal:
|
||||
path: data.AUTH_TYPE
|
||||
value: descope
|
||||
|
||||
- it: accepts dex with an issuer
|
||||
set:
|
||||
tap.auth.enabled: true
|
||||
tap.auth.type: dex
|
||||
tap.auth.oidc.issuer: https://dex.example.com
|
||||
asserts:
|
||||
- equal:
|
||||
path: data.AUTH_TYPE
|
||||
value: dex
|
||||
|
||||
- it: rejects dex without an issuer
|
||||
set:
|
||||
tap.auth.enabled: true
|
||||
tap.auth.type: dex
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorPattern: tap.auth.oidc.issuer is empty
|
||||
|
||||
# Incomplete auth settings are only a problem when auth is on. The default
|
||||
# install ships tap.auth.type=saml with no IdP and must still render.
|
||||
- it: ignores incomplete auth settings while auth is off
|
||||
@@ -52,3 +80,14 @@ tests:
|
||||
- equal:
|
||||
path: data.AUTH_TYPE
|
||||
value: saml
|
||||
|
||||
- it: ignores incomplete oidc settings while auth is off
|
||||
set:
|
||||
tap.auth.type: oidc
|
||||
asserts:
|
||||
- equal:
|
||||
path: data.AUTH_ENABLED
|
||||
value: "false"
|
||||
- equal:
|
||||
path: data.AUTH_TYPE
|
||||
value: oidc
|
||||
|
||||
@@ -70,3 +70,27 @@ tests:
|
||||
mountPath: /var/run/secrets/kubeshark/hub-token
|
||||
name: hub-internal-token
|
||||
readOnly: true
|
||||
|
||||
# The projection is independent of everything that used to feed the old
|
||||
# auth expression, not just of tap.auth.enabled.
|
||||
- it: projects the token regardless of licensing or demo mode
|
||||
set:
|
||||
license: ABC
|
||||
demoModeEnabled: true
|
||||
cloudLicenseEnabled: false
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.volumes
|
||||
content:
|
||||
name: hub-internal-token
|
||||
projected:
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
path: token
|
||||
audience: kubeshark-hub
|
||||
expirationSeconds: 3600
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: HUB_INTERNAL_TOKEN_PATH
|
||||
value: /var/run/secrets/kubeshark/hub-token/token
|
||||
|
||||
@@ -154,7 +154,7 @@ tap:
|
||||
enabled: false
|
||||
type: saml
|
||||
rolesClaim: groups
|
||||
defaultRole: kubeshark-viewer
|
||||
defaultRole: kubeshark-admin
|
||||
groupMapping: {}
|
||||
roles: {}
|
||||
cli:
|
||||
|
||||
@@ -274,7 +274,7 @@ data:
|
||||
AUTH_SAML_IDP_METADATA_URL: ''
|
||||
AUTH_CLI_SERVICE_ACCOUNTS: ''
|
||||
AUTH_ROLES_CLAIM: 'groups'
|
||||
AUTH_DEFAULT_ROLE: 'kubeshark-viewer'
|
||||
AUTH_DEFAULT_ROLE: 'kubeshark-admin'
|
||||
AUTH_GROUP_MAPPING: '{}'
|
||||
AUTH_ROLES: '{}'
|
||||
AUTH_OIDC_ISSUER: 'not set'
|
||||
|
||||
Reference in New Issue
Block a user