indexManagementDashboards plugin breaks with csp.strict: true in OpenSearch Dashboards 3.6.0

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):

OpenSearch: 3.6.0

OpenSearch Dashboards: 3.6.0
Browser: Chrome (latest)

Describe the issue: The indexManagementDashboards plugin throws a CSP error on page load

when csp.strict: true is set. The stack trace points to Ajv calling

new Function() which is blocked by strict CSP.

Configuration: csp.strict: true

Relevant Logs or Screenshots:

EvalError: Evaluating a string as JavaScript violates the following Content

Security Policy directive because ‘unsafe-eval’ is not an allowed source

of script: script-src ‘self’

at new Function (<anonymous>)

at Ajv.compileSchema (indexManagementDashboards.plugin.js:1:32433)

at Ajv.inlineOrCompile (indexManagementDashboards.plugin.js:1:34070)

at Ajv.resolveRef (indexManagementDashboards.plugin.js:1:33878)

at Object.code (indexManagementDashboards.plugin.js:7:20485)

at keywordCode (indexManagementDashboards.plugin.js:4:17410)

  1. What changed in indexManagementDashboards between 3.5.0 and 3.6.0
    that introduced this CSP incompatibility?

  2. What is the recommended way forward — is a fix planned for 3.6.x,
    or is there a supported workaround to use this plugin with csp.strict: true?

@ayush7 Could you share your opensearch_dashboards.yml?

csp.strict: true
opensearch_security.cookie.secure: true
server.customResponseHeaders: { "X-Frame-Options": "DENY" }
server.name: dashboards
server.ssl.supportedProtocols: ["TLSv1.2"]
 
opensearch.username: "kibanaserver"
opensearch.password: "KibanaPassword123!

@rharidas Did you disable multi-tenancy? Could you share your config.yml from OpenSearch security plugin?



\_meta:

  type: "config"

  config_version: 2

config:

  dynamic:

    kibana:

      *#To enable multitenancy set "multitenancy_enabled" to true. server_username is taken from security.sensitiveInfoInSecret.kibanaServerUsr when set, or defaults to kibanaserver.*

      multitenancy_enabled: false

      server_username: kibanaserver

    http:

      anonymous_auth_enabled: false

      xff:

        enabled: false

        internalProxies: ".+"

    authc:

      *# JWT authentication: configure directly here. Set http_enabled: true to enable.*

      *# For static key: leave signing_key blank here. Provide PEM via secret (security.sensitiveInfoInSecret.jwtSigningKy);*

      *# For JWKS: set jwks_uri to your Keycloak JWKS URL and signing_key: null.*

      jwt_auth_domain:

        http_enabled: false

        transport_enabled: false

        order: 0

        http_authenticator:

          type: jwt

          challenge: false

          config:

            signing_key: "" *# Static signing key for JWT validation (leave empty if using jwks_uri)*

            jwks_uri: "" *# URL to fetch JWT public keys from (use if not using static signing_key)*

            jwt_header: "Authorization" *# HTTP header name where JWT token is expected*

            jwt_url_parameter: null *# URL query parameter name for JWT token (optional)*

            jwt_clock_skew_tolerance_seconds: 30 *# Time tolerance in seconds for clock skew validation*

            subject_key: "preferred_username" *# JWT claim that identifies the user*

            roles_key: "roles" *# JWT claim that contains user roles*

            required_issuer: null *# Expected issuer (iss claim) of the JWT token*

            required_audience: null *# Expected audience (aud claim) of the JWT token*

        authentication_backend:

          type: noop

 

      basic_internal_auth_domain:

        http_enabled: true

        transport_enabled: true

        order: 1

        http_authenticator:

          type: "basic"

          challenge: true   *# Set this to false when keycloak authentication or clientcert_auth_domain is enabled*

          config: {}

        authentication_backend:

          type: "intern"

          config: {}

      openid_auth_domain:

        http_enabled: false              *# Set to true to enable keycloak authentication*

        transport_enabled: false

        order: 2

        http_authenticator:

          type: openid

          challenge: false

          config:

            subject_key: preferred_username

            *#Set the same name as configured as Token Claim Name in the client's role-mapper in keycloak*

            roles_key: <roles>

            openid_connect_url: https://<keycloak_ip>:<port>/auth/realms/<realm_name>/.well-known/openid-configuration

            openid_connect_idp:

              enable_ssl: true

              *#Set this to false to disable hostname verification of the IdP's TLS certificate*

              verify_hostnames: true

              *## Set to true when istio is enabled or to disable certificate validation*

              trust_all: false

              *#The value of pemtrustedcas_filepath is set internally. Do not change the value or remove the key.*

              pemtrustedcas_filepath: ""

        authentication_backend:

            type: noop

      proxy_auth_domain:

        http_enabled: false

        transport_enabled: false

        order: 4

        http_authenticator:

          type: "proxy"

          challenge: false

          config:

            user_header: "x-proxy-user"

            *#roles_header: "x-proxy-roles"*

        authentication_backend:

          type: "noop"

          config: {}

      clientcert_auth_domain:

        http_enabled: false

        transport_enabled: false

        order: 3

        http_authenticator:

          type: "clientcert"

          config:

            username_attribute: "cn"

          challenge: false

        authentication_backend:

          type: "noop"

@rharidas Thanks for sharing your files. I’ve reproduced your issue, and this looks like a bug.
I couldn’t find any related issues on GitHub.

Would you mind reporting it in OpenSearch Dashboards GitHub?
If you do so, please share the link here for traceability.

Created an issue :slightly_smiling_face:

@rharidas Thank you. I’ve just commented on the GitHub issue.

Hi ,
After setting the below configuration in dashboards.yaml, we see that the dashboards UI is coming as expected.

csp.loosenCspDirectives: ["script-src", "style-src", "style-src-elem", "worker-src"]

Please let us know if it is ok to set this configuration until a fix is provided. Do you see any security issues ? At-least should be on-par with v3.5.0 wrt to security/vulnerabilities.

Thanks in advanced, waiting for a response.

Hey @pablo :slightly_smiling_face: ,

quick query,
I upgraded to version 3.7.0 and see that this issue does not persist. Has the community fixed this? or is it resolved in version 3.7.0?

@rharidas @maheshmr After testing this using Docker Compose to spin up the official opensearchproject/opensearch and opensearchproject/opensearch-dashboards images and a headless-Chromium (Playwright) script to check for real browser-side CSP violations:

  • The exact reported defect is gone, verified empirically across every major ISM page and with the original plugin combination (ISM + Reports + Security) under strict CSP and without the loosenCspDirectives workaround.
  • Issue #1441 can reasonably be closed as fixed in 3.7.0 via PR #1409.
  • Remaining caveat: no backport to 3.6.x: anyone staying on 3.6.x still needs csp.loosenCspDirectives: ["script-src", "style-src", "style-src-elem", "worker-src"]