Databases

Secure OpenSearch with cnspec

Scan OpenSearch clusters and the security plugin against security and compliance best practices with cnspec.

Scan your OpenSearch clusters to find security risks before they become incidents. cnspec evaluates anonymous access, audit logging, the enabled authentication realms, the internal user database, roles and the index patterns they reach, and role mappings from the OpenSearch security plugin.

cnspec inventories the cluster through read-only requests to the REST API. It never reads your documents.

This provider is for OpenSearch. Elasticsearch serves a different security API and is covered by the separate elasticsearch provider; pointing this one at an Elasticsearch node is detected and refused.

If you're new to cnspec, start with the Quickstart. For an overview of every database cnspec can scan, see the database scanning overview.

Prerequisites

To scan OpenSearch with cnspec, you must have:

Authenticate

cnspec authenticates with basic auth. The security plugin serves HTTPS with a self-signed demo certificate by default, so a default local install typically needs --tls-insecure:

cnspec shell opensearch os.contoso.com --user admin --ask-pass --tls-insecure

For a cluster served with a real CA, verify it instead:

cnspec shell opensearch os.contoso.com --user auditor --ask-pass --tls-ca ca.pem

Prefer a least-privileged account for auditing. With only monitor-level access the cluster resolves while the security posture, users, roles, and role mappings come back empty rather than failing the scan, so confirm they're populated before trusting a passing check that reads them.

Connection options

OptionDescription
--hostCluster hostname or IP address (also accepted as the positional argument)
--portREST API port (default 9200)
--schemehttp or https (default https)
--user, -uUser for basic authentication
--password, -pPassword, or --ask-pass to be prompted
--tls-caPath to a CA certificate to verify the cluster
--tls-insecureSkip TLS certificate verification, for the default self-signed demo certificate

Verify with a quick OpenSearch check

cnspec shell opensearch os.contoso.com --user admin --ask-pass --tls-insecure
cnspec> opensearch.cluster { name version distribution healthStatus nodeCount }
opensearch.cluster: {
  name: "docker-cluster"
  version: "2.17.1"
  distribution: "opensearch"
  healthStatus: "yellow"
  nodeCount: 1
}

If cnspec connects and shows the version, you're ready to scan.

Scan OpenSearch

cnspec scan opensearch os.contoso.com --user auditor --ask-pass

When a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.

Mondoo doesn't yet ship an out-of-the-box OpenSearch policy, so use the checks below as a starting point and create your own policies to meet your specific requirements.

Explore and test checks interactively

cnspec shell opensearch os.contoso.com --user auditor --ask-pass

Read the security posture

cnspec> opensearch.cluster.security { anonymousAccessEnabled auditLoggingEnabled doNotFailOnForbidden enabledAuthRealms }
opensearch.cluster.security: {
  anonymousAccessEnabled: false
  auditLoggingEnabled: true
  doNotFailOnForbidden: false
  enabledAuthRealms: ["basic_internal_auth_domain"]
}

List internal users

cnspec> opensearch.cluster.users { name isReserved isStatic securityRoles backendRoles }

List roles and their cluster permissions

cnspec> opensearch.cluster.roles { name isReserved clusterPermissions }

Inspect a role's index permissions

cnspec> opensearch.cluster.roles.where(name == "readers").first.indexPermissions { indexPatterns allowedActions hasFieldLevelSecurity hasFieldMasking }

List role mappings

cnspec> opensearch.cluster.roleMappings { name users backendRoles hosts }

Example security checks

Ensure anonymous access is disabled

cnspec> opensearch.cluster.security.anonymousAccessEnabled == false
[ok] value: true

Ensure audit logging is enabled

cnspec> opensearch.cluster.security.auditLoggingEnabled == true
[ok] value: true

Ensure authorization failures are not hidden

doNotFailOnForbidden filters results instead of returning a 403, which makes an over-broad or under-privileged role hard to notice:

cnspec> opensearch.cluster.security.doNotFailOnForbidden == false
[ok] value: true

Ensure an authentication realm is configured

cnspec> opensearch.cluster.security.enabledAuthRealms.length > 0
[ok] value: true

Ensure no custom role grants every cluster permission

cnspec> opensearch.cluster.roles.where(isReserved == false).none(clusterPermissions.contains("*"))
[ok] value: true

Ensure no custom role grants every action on every index

cnspec> opensearch.cluster.roles.where(isReserved == false).all(indexPermissions.none(indexPatterns.contains("*") && allowedActions.contains("*")))
[ok] value: true

Ensure all_access is not mapped broadly

all_access is the built-in administrator role, and a mapping is how someone actually receives it:

cnspec> opensearch.cluster.roleMappings.where(name == "all_access") { users backendRoles hosts }

Ensure no role mapping matches on host alone

A host-based mapping grants the role to anything connecting from that address, with no regard for who is connecting:

cnspec> opensearch.cluster.roleMappings.all(hosts.length == 0)
[ok] value: true

Ensure the demo internal users have been removed

A default install ships with well-known accounts such as kibanaserver and logstash:

cnspec> opensearch.cluster.users.where(isReserved == false && isStatic == false) { name securityRoles }

Ensure hidden roles are reviewed

A hidden role doesn't appear in the security dashboards but still grants what it grants:

cnspec> opensearch.cluster.roles.where(isHidden) { name clusterPermissions }

Review roles that read every field

Field-level security and field masking are what keep a broad read grant from exposing sensitive columns:

cnspec> opensearch.cluster.roles.where(isReserved == false) { name indexPermissions.where(hasFieldLevelSecurity == false && hasFieldMasking == false) { indexPatterns allowedActions } }

Learn more

OpenSearch masks user password hashes in the security API, so the provider doesn't report whether a user has a password set.

On this page