Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):
Opensearch and dashboards docker 3.2.0,
Keycloak - Version 26.3.2
Describe the issue:
I want to setup SingleSign on to Opensearch with keycloak and SAML, however when I click on “Log in with single-sign on” browser got redirected to https://opensearch.example.com:5601/auth/saml/login?redirectHash=false and I get an error message: “{“statusCode”:500,“error”:“Internal Server Error”,“message”:“Internal Error”}”
Configuration:
opensearch.yml:
_meta:
type: "config"
config_version: 2
config:
dynamic:
http:
anonymous_auth_enabled: false
authc:
basic_internal_auth_domain:
order: 0
description: "HTTP basic authentication using the internal user database"
http_enabled: true
transport_enabled: true
http_authenticator:
type: basic
challenge: false
authentication_backend:
type: internal
saml_auth_domain:
order: 1
description: "SAML provider"
http_enabled: true
transport_enabled: true
http_authenticator:
type: saml
challenge: true
config:
idp:
metadata_url: http://keycloak:8080/realms/boundary/protocol/saml/descriptor
sp:
entity_id: opennsearch
kibana_url: https://opensearch-dashboards:5601
roles_key: groups
exchange_key: eb96d42cd351aced3b90b2be44c990c2e4534644e5c098cbd83297f3a175170f #openssl rand -hex 32
authentication_backend:
type: noop
opensearch-dashboards.yml
server.name: opensearch-dashboards
server.host: "0.0.0.0"
server.ssl.enabled: true
server.ssl.certificate: "/opt/certs/server.crt"
server.ssl.key: "/opt/certs/server.key"
opensearch.ssl.certificateAuthorities: ["/opt/certs/rootCA.crt"]
opensearch.ssl.verificationMode: none
opensearch.username: kibanaserver
opensearch.password: kibanaserver
opensearch.requestHeadersWhitelist: ["securitytenant", "security_tenant", "Authorization"]
opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"]
opensearch_security.readonly_mode.roles: ["kibana_read_only"]
opensearch_security.cookie.secure: false
opensearch_security.auth.type: ["basicauth","saml"]
opensearch_security.auth.multiple_auth_enabled: true
server.xsrf.allowlist: [ "/_opendistro/_security/saml/acs/idpinitiated", "/_opendistro/_security/saml/acs", "/_opendistro/_security/saml/logout", "/_plugins/_security/saml/acs/idpinitiated", "/_plugins/_security/saml/acs", "/_plugins/_security/saml/logout", "/_opendistro/_security/saml/acs" ]
docker-compose.yml
services:
opensearch1:
image: opensearchproject/opensearch:3.2.0
environment:
- cluster.name=opensearch-cluster
- node.name=opensearch1
- discovery.seed_hosts=opensearch1,opensearch2
- cluster.initial_master_nodes=opensearch1,opensearch2
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=gqYeDIzbEwTTYmB7
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- opensearch-data1:/usr/share/opensearch/data
- ./configs/opensearch.yml:/usr/share/opensearch/plugins/opensearch-security/securityconfig/config.yml
ports:
- 9200:9200
- 9600:9600
networks:
- opensearch-net
opensearch2:
image: opensearchproject/opensearch:3.2.0
environment:
- cluster.name=opensearch-cluster
- node.name=opensearch2
- discovery.seed_hosts=opensearch1,opensearch2
- cluster.initial_master_nodes=opensearch1,opensearch2
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=gqYeDIzbEwTTYmB7
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- opensearch-data2:/usr/share/opensearch/data
- ./configs/opensearch.yml:/usr/share/opensearch/plugins/opensearch-security/securityconfig/config.yml
networks:
- opensearch-net
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:3.2.0
ports:
- 5601:5601
expose:
- "5601"
environment:
OPENSEARCH_HOSTS: '["https://opensearch1:9200","https://opensearch2:9200"]'
volumes:
- ./configs/opensearch-dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
- ./configs/certs:/opt/certs
networks:
- opensearch-net
volumes:
opensearch-data1:
opensearch-data2:
networks:
opensearch-net:
external: true
name: my_network #docker network create my_network
keycloak docker-compose.yml
services:
keycloak:
image: quay.io/keycloak/keycloak:26.3.2
restart: always
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://pg:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_HTTP_ENABLED: "true"
KC_HTTPS_ENABLED: "true"
KC_HOSTNAME_STRICT_HTTPS: "false"
PROXY_ADDRESS_FORWARDING: "true"
KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/certs/server.crt
KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/certs/server.key
KC_LOG_LEVEL: info
KC_METRICS_ENABLED: true
KC_HEALTH_ENABLED: true
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
entrypoint: ["/opt/keycloak/bin/kc.sh"]
command: [
"start-dev",
"--features=token-exchange,organization,admin-fine-grained-authz,scripts,client-policies",
"--http-port", "8080",
"--https-port", "8443"
]
ports:
- 8080:8080
- 8443:8443
volumes:
- ./certs:/opt/keycloak/certs
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8080" ]
interval: 5s
timeout: 5s
retries: 3
start_period: 5s
networks:
- "infra"
pg:
image: postgres:16.4
container_name: pg
ports:
- 5432:5432
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
PGUSER: keycloak
POSTGRES_PASSWORD: keycloak
healthcheck:
test: ["CMD-SHELL", "pg_isready -d keycloak -U keycloak"]
interval: 3s
timeout: 5s
retries: 5
networks:
- "infra"
networks:
infra:
external: true
name: my_network #docker network create my_network
terraform keycloak
resource "keycloak_realm" "realm" {
realm = "boundary"
enabled = true
registration_allowed = false
registration_email_as_username = false
reset_password_allowed = true
remember_me = true
verify_email = true
login_with_email_allowed = true
duplicate_emails_allowed = false
access_token_lifespan = "12h"
}
resource "keycloak_realm_events" "events" {
realm_id = keycloak_realm.realm.id
admin_events_enabled = true
admin_events_details_enabled = true
events_listeners = ["jboss-logging"]
events_enabled = true
}
resource "keycloak_oidc_google_identity_provider" "google" {
provider_id = "google"
realm = keycloak_realm.realm.id
client_id = "apps.googleusercontent.com"
client_secret = "GOCS"
request_refresh_token = true
default_scopes = "openid profile email"
accepts_prompt_none_forward_from_client = false
trust_email = true
link_only = false
}
resource "keycloak_group" "developers" {
realm_id = keycloak_realm.realm.id
name = "developers"
}
resource "keycloak_saml_client" "app" {
realm_id = keycloak_realm.realm.id
client_id = "opennsearch"
name = "opennsearch"
client_signature_required = false
sign_assertions = false
name_id_format = "email"
include_authn_statement = false
force_post_binding = true
force_name_id_format = true
sign_documents = true
signature_algorithm = "RSA_SHA256"
signature_key_name = "NONE"
valid_redirect_uris = [
"http://127.0.0.1:8000/api/saml/callback",
"https://127.0.0.1:8443/api/saml/callback",
"http://127.0.0.1:5601/_opendistro/_security/saml/acs",
"http://127.0.0.1:5601/_plugins/_security/saml/acs",
]
}
resource "keycloak_saml_client_default_scopes" "this" {
realm_id = keycloak_realm.realm.id
client_id = keycloak_saml_client.app.id
default_scopes = []
}
resource "keycloak_generic_protocol_mapper" "groups" {
realm_id = keycloak_realm.realm.id
client_id = keycloak_saml_client.app.id
name = "groups"
protocol = "saml"
protocol_mapper = "saml-group-membership-mapper"
config = {
"attribute.name" = "groups"
"attribute.nameformat" = "Basic"
"friendly.name" = "groups"
"full.path" = "false"
"single" = "true"
}
}
resource "keycloak_saml_user_property_protocol_mapper" "email" {
realm_id = keycloak_realm.realm.id
client_id = keycloak_saml_client.app.id
name = "email"
friendly_name = "email"
user_property = "email"
saml_attribute_name = "email"
saml_attribute_name_format = "Basic"
}
Relevant Logs or Screenshots: