Skip to main content

OpenSearch configuration

Environment variables

Open the service details (the "..." button, then Details) to see the variables it provides. With the default prefix DEFAULT, your application receives values like the following:

# Backend configuration
DEFAULT_SEARCH_BACKEND=opensearch-multi-index
DEFAULT_SEARCH_AUTH_SCHEME=aws-v4-auth
DEFAULT_SEARCH_VERSION=3.7.0

# Connection details
DEFAULT_SEARCH_HOSTNAME=search-cluster-psckcd7m2b6d5iiijunwsyvo34.eu-central-1.es.amazonaws.com
DEFAULT_SEARCH_PORT=443
DEFAULT_SEARCH_ACCESS_KEY_ID=AKIA...
DEFAULT_SEARCH_SECRET_ACCESS_KEY=SECRET...

# Full connection string and Haystack URL (credentials are URL-encoded)
DEFAULT_SEARCH_DSN=https://AKIA...:SECRET...@search-cluster-psckcd7m2b6d5iiijunwsyvo34.eu-central-1.es.amazonaws.com:443/myapp-live-7303e23cd7e9497aa6b25789c5a6e6-be706cf-*
DEFAULT_SEARCH_HAYSTACK_URL=es+https+aws://AKIA...:SECRET...@search-cluster-psckcd7m2b6d5iiijunwsyvo34.eu-central-1.es.amazonaws.com:443/myapp-live-7303e23cd7e9497aa6b25789c5a6e6-be706cf-*

# Index prefix constraint
DEFAULT_SEARCH_INDEX_PREFIX=myapp-live-7303e23cd7e9497aa6b25789c5a6e6-be706cf-*

If you use a different prefix, replace DEFAULT_ with your own prefix.

We recommend building the connection from the individual variables rather than parsing the DSN.

Authentication

Authentication is AWS SigV4 (IAM), not HTTP basic authentication.

DEFAULT_SEARCH_ACCESS_KEY_ID and DEFAULT_SEARCH_SECRET_ACCESS_KEY are AWS IAM credentials, and they are used to sign each request. You cannot pass them as a username and password, even though they appear inside the DSN.

Most OpenSearch clients support this out of the box. In Python, opensearch-py provides AWSV4SignerAuth, which needs to be paired with RequestsHttpConnection. See the configuration examples.

Index naming rules

DEFAULT_SEARCH_INDEX_PREFIX is a pattern, not an index name. It ends with * and describes every index your application is allowed to touch.

Index names cannot contain *, so your application has to build a real name by removing the wildcard and adding its own suffix:

prefix = os.environ["DEFAULT_SEARCH_INDEX_PREFIX"].rstrip("*")
index_name = f"{prefix}default" # myapp-live-...-be706cf-default

Your credentials only allow index names that match the pattern:

Index nameResult
myapp-live-7303e23cd7e9497aa6b25789c5a6e6-be706cf-defaultallowed
myapp-live-7303e23cd7e9497aa6b25789c5a6e6-be706cf-another-indexallowed
defaultdenied
myapp-test-7303e23cd7e9497aa6b25789c5a6e6-ab3121a-indexdenied
anotherapp-live-123afde4de3321afe45610eabce234-ab3121a-defaultdenied

The reason for this restriction is that the AWS permissions model could otherwise allow aliases to bypass the intended access restrictions.

Cluster limitations

Applications share a managed cluster, and your credentials are scoped to your index prefix. Cluster-level API paths are therefore not available to your application:

  • GET / is denied, and so are /_cluster/health and /_cat/indices. Anything that reads cluster information or cluster health as a readiness check will get HTTP 403. Point health checks at your own index instead, for example a _count on it.
  • Searches must name an index. POST /_search without an index, and /_all/_search, are denied. Libraries such as Haystack always address the index by name, so this only affects hand-written queries.
  • The scroll API (/_search/scroll) is not available. Instead, use the sort parameter with the search_after parameter to scroll responses for user queries.

If you need cluster-level access, a dedicated cluster is required. Contact our support team.

Troubleshooting

SymptomLikely cause
HTTP 403 on indexing, empty index after rebuild_indexthe request went to a cluster-level endpoint (/_bulk, /_search) instead of your index, or the index name is outside your prefix
HTTP 403 on a health checkthe check reads GET /, /_cluster/health or /_cat/indices. Use a _count on your own index instead
UnsupportedProductError, or the client refuses to connectan Elasticsearch client is being used instead of an OpenSearch one. elasticsearch-py 7.14 and later run a product check against the server, and 8.x fails outright
Invalid index name errorthe index name still contains the * from DEFAULT_SEARCH_INDEX_PREFIX
Autocomplete returns nothingthe mapping lost its analyzer on EdgeNgramField or NgramField. See the fixes in the Django section
HTTP 400 when sorting or facetingyou are sorting or faceting on an analyzed text field. Declare the field with faceted=True and use the <field>_exact keyword field, or sort on a date or integer field
HTTP 400 mentioning types or doc_typemapping types no longer exist. They were removed in Elasticsearch 7 and OpenSearch never supported them

If you need support, contact us.