Configure OpenSearch SSO with Authentik
ClusterNest Managed OpenSearch can delegate Dashboards login to Authentik over either OIDC or SAML. Pick one - auth_type accepts only a single mode per cluster.
You'll need your cluster's OpenSearch Dashboards hostname before registering the app in Authentik. Set opensearch_dashboards_custom_hostname so you know it upfront, or create the cluster first with auth_type = "internal" and note the generated opensearch_dashboards_url output before switching it over.
- OIDC
- SAML
OIDC
Authentik's default ID token doesn't include a groups claim unless the groups scope is attached to the provider - without it, drop roles_key and rely on OpenSearch's internal role mapping by username (subject_key, default preferred_username) instead.
- Console
- Terraform
- In Authentik, go to Applications > Providers > Create, type OAuth2/OpenID Provider.
- Client type: Confidential
- Redirect URIs:
https://<dashboards-hostname>/auth/openid/login(Strict, or a regex match if the hostname isn't final yet) - Scopes: include
openid,email,profile, and addgroupsif you want role mapping via group membership.
- Go to Applications > Applications > Create, give it a slug (e.g.
opensearch), and link it to the provider above. - Open the provider again - it now shows the Client ID and Client Secret.
connect_url is https://<authentik-host>/application/o/<app-slug>/.well-known/openid-configuration.
In the ClusterNest console, open the cluster's create/edit form and set Authentication Type to OIDC, then fill in:
- Connect URL:
https://auth.example.com/application/o/opensearch/.well-known/openid-configuration - Client ID / Client Secret: from the provider page
- Roles Key:
groups(leave blank to skip role mapping)
Authentik has an official provider (goauthentik/authentik) that can create the OAuth2 provider and application, wired directly into the same config as the ClusterNest cluster:
terraform {
required_providers {
authentik = {
source = "goauthentik/authentik"
version = "~> 2026.5"
}
clusternest = {
source = "tf.clusternest.com/clusternest/clusternest"
version = ">=1.1.0"
}
}
}
provider "authentik" {
url = "https://auth.example.com"
token = var.authentik_token
}
provider "clusternest" {
email = "[email protected]"
password = var.clusternest_app_password
}
locals {
dashboards_hostname = "opensearch-dashboards.example.com"
}
data "authentik_flow" "authorization" {
slug = "default-provider-authorization-implicit-consent"
}
data "authentik_flow" "invalidation" {
slug = "default-provider-invalidation-flow"
}
resource "authentik_provider_oauth2" "opensearch" {
name = "opensearch"
client_id = "opensearch"
authorization_flow = data.authentik_flow.authorization.id
invalidation_flow = data.authentik_flow.invalidation.id
allowed_redirect_uris = [
{
matching_mode = "strict"
url = "https://${local.dashboards_hostname}/auth/openid/login"
}
]
}
resource "authentik_application" "opensearch" {
name = "OpenSearch"
slug = "opensearch"
protocol_provider = authentik_provider_oauth2.opensearch.id
}
resource "clusternest_opensearch" "sso" {
name = "logs"
tier = "standard"
organization_id = 123
auth_type = "oidc"
oidc_config = {
connect_url = "https://auth.example.com/application/o/${authentik_application.opensearch.slug}/.well-known/openid-configuration"
client_id = authentik_provider_oauth2.opensearch.client_id
client_secret = authentik_provider_oauth2.opensearch.client_secret
roles_key = "groups"
}
opensearch_dashboards_custom_hostname = local.dashboards_hostname
}
client_secret is left unset on the provider so Authentik generates one - it comes back as a sensitive computed attribute. Add the groups scope to authentik_provider_oauth2.opensearch if you're using roles_key.
SAML
roles_key defaults to an ADFS-style claim URI - it won't match anything Authentik emits unless you add a matching Property Mapping to the provider. Point it at whatever SAML attribute name your Property Mappings actually produce, or drop it if you're not mapping roles.
- Console
- Terraform
- In Authentik, go to Applications > Providers > Create, type SAML Provider.
- ACS URL:
https://<dashboards-hostname>/_opendistro/_security/saml/acs - Issuer: the value you'll use as
sp_entity_idbelow (any identifier you choose, e.g.opensearch-dashboards) - Service Provider Binding: Post
- ACS URL:
- Go to Applications > Applications > Create, give it a slug (e.g.
opensearch), and link it to the provider above. - Open the provider's detail page - it shows a metadata URL in the form
https://<authentik-host>/api/v3/providers/saml/<id>/metadata/?download. That's youridp_metadata_url. - The entity ID Authentik issues for this app is
https://<authentik-host>/application/saml/<app-slug>/metadata/- use it asidp_entity_id. It must match exactly (including trailing slash) or OpenSearch Dashboards will reject the assertion with "Authentication finally failed".
In the ClusterNest console, open the cluster's create/edit form and set Authentication Type to SAML, then fill in:
- IDP Metadata URL:
https://auth.example.com/api/v3/providers/saml/3/metadata/?download - IDP Entity ID:
https://auth.example.com/application/saml/opensearch/metadata/ - SP Entity ID:
opensearch-dashboards - Roles Key:
http://schemas.xmlsoap.org/claims/Group(only if you added a matching Property Mapping)
terraform {
required_providers {
authentik = {
source = "goauthentik/authentik"
version = "~> 2026.5"
}
clusternest = {
source = "tf.clusternest.com/clusternest/clusternest"
version = ">=1.1.0"
}
}
}
provider "authentik" {
url = "https://auth.example.com"
token = var.authentik_token
}
provider "clusternest" {
email = "[email protected]"
password = var.clusternest_app_password
}
locals {
dashboards_hostname = "opensearch-dashboards.example.com"
}
data "authentik_flow" "authorization" {
slug = "default-provider-authorization-implicit-consent"
}
data "authentik_flow" "invalidation" {
slug = "default-provider-invalidation-flow"
}
resource "authentik_provider_saml" "opensearch" {
name = "opensearch"
authorization_flow = data.authentik_flow.authorization.id
invalidation_flow = data.authentik_flow.invalidation.id
acs_url = "https://${local.dashboards_hostname}/_opendistro/_security/saml/acs"
sp_binding = "post"
}
resource "authentik_application" "opensearch" {
name = "OpenSearch"
slug = "opensearch"
protocol_provider = authentik_provider_saml.opensearch.id
}
resource "clusternest_opensearch" "sso" {
name = "logs"
tier = "standard"
organization_id = 123
auth_type = "saml"
saml_config = {
idp_metadata_url = "https://auth.example.com/api/v3/providers/saml/${authentik_provider_saml.opensearch.id}/metadata/?download"
idp_entity_id = "https://auth.example.com/application/saml/${authentik_application.opensearch.slug}/metadata/"
sp_entity_id = "opensearch-dashboards"
roles_key = "http://schemas.xmlsoap.org/claims/Group"
}
opensearch_dashboards_custom_hostname = local.dashboards_hostname
}
Add a property_mappings entry on authentik_provider_saml.opensearch (an authentik_property_mapping_provider_saml resource) if you want roles_key to actually carry group data - otherwise drop it.
See the Terraform resource reference for the full field list.