Connector

OpenSearch access governance — every query reviewed before it runs

Last updated

AccessFlow governs OpenSearch through the same submit, analyse, approve, execute pipeline as any other engine. OpenSearch speaks the same REST API and Query DSL as Elasticsearch for everything AccessFlow governs, so it is served by the same engine plugin — the two differ only in the HTTP client stack underneath.

Family
Search
Query language
JSON Query DSL
Runs as
Engine plugin (shared with Elasticsearch)
Default port
9200
Default SSL mode
REQUIRE
Install
One-click from the connector catalog

How AccessFlow connects

OpenSearch and Elasticsearch share one plugin JAR, which registers two engine providers. They genuinely need separate code at exactly one layer: Elasticsearch ships on one major version of the Apache HTTP client and OpenSearch on the next, so the JAR bundles both stacks, each relocated separately, behind a small transport abstraction. Parsing, row security, masking and introspection are shared code.

The base URL is built from host and port (9200 by default) with the scheme from the SSL mode, or supplied verbatim. Authentication is HTTP basic or an API key held in its own encrypted field.

What AccessFlow understands

The same JSON envelope as Elasticsearch: the first recognised command key names the operation and its value is the target index. search and count are reads, with get and mget lowered into a search so there is one row-security path; index and bulk are inserts; update_by_query and delete_by_query are updates and deletes; index and mapping management is DDL.

What it refuses

Scripting is refused anywhere in the request tree — script, script_fields, script_score, scripted_metric and runtime_mappings — along with cluster-level APIs and any index name beginning with an underscore or a dot. A bulk request may carry only index actions, so a submission classifies as exactly one kind of write.

Row-level security and masking

The user's query is wrapped rather than merged: it becomes the must clause of a new boolean query whose filter holds the policy clauses, which is what makes the rewrite provably non-widening. An empty value list becomes a negated match-all and therefore matches nothing.

A write into a policied index is rejected. As on Elasticsearch, term clauses match exact keyword fields, so a policy on an analysed text field matches tokens rather than the literal value — check the field type introspection reports before writing the policy. Masking recurses by dot-path into nested objects.

What the rewrite actually does

A policy restricting the orders index to the caller's region wraps the submitted query rather than merging into it:

JSON Query DSL
// submitted
{ "search": "orders", "query": { "match": { "status": "OPEN" } } }

// executed — the original query becomes must, the policy becomes filter
{ "search": "orders",
  "query": { "bool": { "must":   [ { "match": { "status": "OPEN" } } ],
                       "filter": [ { "term":  { "region": "EU" } } ] } } }

Wrapping rather than merging is what makes the rewrite provably non-widening. An empty policy value list becomes a negated match-all and therefore matches nothing.

Introspection

The connection test issues a cluster-info request, and introspection reads index mappings into tables and dot-path columns with a synthetic id primary key. Searches page to one more than the row cap for truncation detection, and a timed-out search or a failed bulk becomes an execution error rather than a partial success.

What is shared with Elasticsearch, and what is not

OpenSearch has its own catalog entry, manifest and database type because the connector catalog allows one connector per dialect — not because the governance behaviour differs. Both manifests pin the same JAR by the same SHA-256, and the catalog picks the right provider out of it by matching the connector id against the engine id at load time.

There is exactly one layer where the code genuinely diverges, and it is not a governance layer: Elasticsearch and OpenSearch ship on different major versions of the Apache HTTP client. The JAR therefore bundles both stacks, each relocated under its own package prefix so they cannot collide, behind a small transport abstraction. Everything above that line — the query parser, the classification, the scripting ban, the bool-filter row security, the dot-path masker and introspection — is one implementation used by both.

So every limit documented on the Elasticsearch connector page applies here unchanged, including the important one: a row-security policy pointed at an analysed text field matches tokens rather than the literal value, because term clauses only match exact keyword fields.