Kubesense

Okta SAML

Overview

This article describes how to set up SAML 2.0 single sign-on (SSO) for KubeSense using Okta as the identity provider (IdP).

Once configured, users sign in to KubeSense with their Okta credentials, inheriting your organization's Okta policies — MFA, conditional access, and lifecycle management.

info: KubeSense federates with one SAML IdP per deployment. Choose either Okta or Google SAML, not both. The provider setting selects which.

Prerequisites

  • An Okta organization with super administrator access
  • A KubeSense deployment reachable at a public HTTPS URL (e.g. https://kubesense.example.com)
  • The ability to run helm upgrade against the deployment

Step 1: Create the SAML app in Okta

  1. In the Okta Admin Console, go to ApplicationsApplications
  2. Click Create App Integration
  3. Select SAML 2.0 and click Next
  4. On General Settings, enter App name: KubeSense, then click Next

info: Use Create App Integration, not the Okta Integration Network submission wizard. The OIN wizard is for publishing an app to Okta's public catalog for other organizations to install — it is not needed to connect your own tenant.

Step 2: Configure SAML settings

On the Configure SAML page, enter the following exactly:

FieldValue
Single sign-on URLhttps://<KUBESENSE_DOMAIN>/api/saml/acs
Audience URI (SP Entity ID)https://<KUBESENSE_DOMAIN>/saml
Default RelayState(leave blank)
Name ID formatEmailAddress
Application usernameEmail

Replace <KUBESENSE_DOMAIN> with your actual domain, with no trailing slash.

warning: The Single sign-on URL includes the /api prefix. KubeSense mounts its SAML endpoints under /api/saml/*; a URL without /api fails assertion validation with a Destination mismatch.

Attribute statements (required)

Unlike Google Workspace, an Okta SAML app sends no attributes by default. KubeSense identifies users by email, so these must be added or every login is rejected.

Under Attribute Statements, add:

NameName formatValue
emailUnspecifieduser.email
firstNameUnspecifieduser.firstName
lastNameUnspecifieduser.lastName

Group attribute statements (optional)

Only needed if you want Okta groups to determine KubeSense roles — see Map Okta groups to roles.

Under Group Attribute Statements, add:

NameFilterValue
groupsMatches regex.*

Click Next, choose I'm an Okta customer adding an internal app, then Finish.

Leave request signing off

On the app's General tab, leave Signed Requests disabled. KubeSense signs its AuthnRequests with RSA-SHA1, which Okta rejects when request-signature validation is enabled. Okta does not require request signing, and assertion signing (which Okta always does) is what KubeSense verifies.

Step 3: Get the IdP metadata

  1. Open the app's Sign On tab
  2. Under SAML Signing CertificatesActionsView IdP metadata, or copy the Metadata URL
  3. Save the XML — you will paste it into the KubeSense config in Step 5

The metadata URL looks like:

https://<your-org>.okta.com/app/<app-id>/sso/saml/metadata

Step 4: Assign the app to users

A newly created Okta app is assigned to nobody. Until you assign it, users get an Okta error before ever reaching KubeSense.

  1. Open the app's Assignments tab
  2. AssignAssign to People (or Assign to Groups)
  3. Select the users or groups who should have access, then Save

Step 5: Configure KubeSense via Helm values

api:
  saml:
    enabled: true
    rootUrl: "https://<KUBESENSE_DOMAIN>"
    entityId: "https://<KUBESENSE_DOMAIN>/saml"
    # Paste the IdP metadata XML from Step 3.
    idpMetadataXml: |
      <?xml version="1.0" encoding="UTF-8"?>
      <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://www.okta.com/...">
        ...full XML body...
      </md:EntityDescriptor>
  # Selects the Okta IdP flavour. Supplied via a Secret because the chart does
  # not yet expose `api.saml.provider` as a first-class value.
  extraEnvVarsSecret: kubesense-okta-saml

webapp:
  extraEnv:
    # Renders the "Sign In with Okta SAML" button.
    ENABLE_SAML: "true"
    SAML_PROVIDER: "okta"

Create the Secret that carries the provider setting:

kubectl create secret generic kubesense-okta-saml \
  --namespace <KUBESENSE_NAMESPACE> \
  --from-literal=SAML_PROVIDER=okta

Then apply:

helm upgrade kubesense ./charts/kubesense-server \
  -f values.yaml \
  --set-file api.saml.idpMetadataXml=./OktaIDPMetadata.xml

info: webapp.extraEnv.SAML_PROVIDER only controls which logo and label the sign-in button shows. The API's SAML_PROVIDER is what actually selects the IdP behaviour. Keep the two identical, or users will see a Google button that performs an Okta login.

What the chart handles for you

  • kubesense-saml-secret — created on first install with a random 32-byte master key, preserved across upgrades via lookup
  • API ConfigMap — rendered with SAML_ENABLED, SAML_ENTITY_ID, SAML_ROOT_URL, SAML_IDP_METADATA_XML
  • API DeploymentenvFrom-wired to kubesense-saml-secret so SAML_KEY_ENCRYPTION_KEY is injected
  • SP signing key — the API generates a self-signed cert + RSA-2048 key on first SAML init, encrypts it with AES-256-GCM, and persists it in the saml_sp_keys table. Restarts reuse the same key.

Configuration reference

api.saml

FieldRequiredDescription
enabledyesRegisters the /api/saml/* routes
rootUrlyesPublic HTTPS URL of the deployment
entityIdyesSP Entity ID — must equal Okta's Audience URI, byte-for-byte
idpMetadataXmlone of twoInline IdP metadata XML (recommended)
idpMetadataUrlone of twoMetadata URL fetched at startup — adds a startup dependency on Okta

API environment variables

VariableDefaultDescription
SAML_PROVIDERgooglegoogle or okta. Selects the requested NameID format, the auth_provider recorded on users, and audit wording.
SAML_NAMEID_FORMATper providertransient, emailaddress, persistent or unspecified. Empty means Google → transient, Okta → emailaddress.
SAML_GROUPS_ATTRIBUTEgroupsAssertion attribute carrying group membership
SAML_SYNC_ROLE_ON_LOGINfalseRe-apply group→role mapping on every login
SAML_KEY_ENCRYPTION_KEY32-byte AES key (hex or base64). Injected by the chart.

Webapp environment variables

VariableDefaultDescription
ENABLE_SAML(unset)true shows the SAML button. When unset, falls back to the legacy ENABLE_GOOGLE_SAML.
SAML_PROVIDERgooglegoogle or okta. Button label and icon only.

Step 6: Verify SSO

  1. Open https://<KUBESENSE_DOMAIN>/login in a private browser window
  2. Click Sign In with Okta SAML
  3. Authenticate with your Okta account
  4. You should land on the KubeSense dashboard

New users are provisioned automatically on first login with the User role.

Map Okta groups to roles

By default every SAML user is created with the User role, and administrators are promoted manually in KubeSense. To let Okta groups drive roles instead, configure a mapping.

warning: Group mapping is read from the API's config.yaml file. It cannot be supplied through an environment variable, because a map cannot be expressed as a single env value — so this requires mounting a config file into the API pod rather than using the chart's env-based configuration.

saml:
  enabled: true
  provider: okta
  groups_attribute: "groups"
  group_role_map:
    kubesense-admins: Admin
    kubesense-users: User
  sync_role_on_login: false

Behaviour:

  • Group names match case-insensitively
  • A user in several mapped groups receives the highest-privilege match
  • Groups with no mapping are ignored; the user falls back to User
  • An unknown role type in the map fails at startup rather than silently downgrading users
  • sync_role_on_login: true re-applies the mapping on every login, so revoking an Okta group demotes the user at next sign-in. Left false, a role edited in the KubeSense UI is preserved.

Valid role types are Admin, User and Internal.

Single Logout

KubeSense does not implement SAML Single Logout. Signing out of KubeSense ends the KubeSense session only; the Okta session remains active. Leave the app's Single Logout setting disabled.

Rotate the IdP certificate

Okta rotates SAML signing certificates when you generate a new one or when an app is re-created:

  1. Open the app's Sign On tab and view the IdP metadata
  2. Replace api.saml.idpMetadataXml in your Helm values
  3. Run helm upgrade — the chart re-renders the API ConfigMap and the Deployment rolls automatically

Troubleshooting

SymptomCauseFix
503 SAML is not availableSAML handler failed at startupThe real reason is logged. Run kubectl logs deployment/kubesense-api | grep "Failed to initialize SAML handler"
503 and logs show saml_sp_keys ... doesn't existTable missing from the databaseApply migration 1.0.53_saml_sp_keys.sql
503 and logs show SAML_KEY_ENCRYPTION_KEY env var is requiredSecret not mountedConfirm kubesense-saml-secret exists and the API Deployment references it
403 InvalidNameIDPolicy from OktaRequested NameID format disagrees with the appSet the app's Name ID format to EmailAddress, or set SAML_NAMEID_FORMAT to match the app
400 SAML assertion missing email attributeAttribute statements not configuredAdd the email attribute statement from Step 2
401 SAML assertion validation failedDeliberately generic; real reason is loggedCheck logs for SAML: failed to parse/validate assertion and its private_detail field
private_detail: "Destination does not match"Single sign-on URL ≠ <rootUrl>/api/saml/acsFix the URL in Okta — remember the /api prefix
private_detail: "Audience does not match"Entity ID mismatchMake Okta's Audience URI equal api.saml.entityId exactly
private_detail: "Signature could not be verified"Stale IdP metadata after certificate rotationRe-copy the metadata and helm upgrade
Okta error before reaching KubeSenseApp not assignedComplete Step 4
Okta rejects the AuthnRequest signatureRequest signature validation enabledDisable Signed Requests on the app
Login completes but bounces to /loginAuth cookies not storedKubeSense must be served over HTTPS — the cookies are Secure — and rootUrl must match the URL the browser actually uses
Button says "Google SAML" but signs in with OktaWebapp and API disagreeSet webapp.extraEnv.SAML_PROVIDER to okta to match the API