From 53ba6cbd44fd22ce1c659a6de09d41b84ab2530a Mon Sep 17 00:00:00 2001 From: as51340 Date: Tue, 4 Aug 2026 12:39:38 +0200 Subject: [PATCH 1/5] feat: SSO coords --- pages/clustering/high-availability.mdx | 5 + pages/clustering/high-availability/_meta.ts | 1 + .../coordinator-authentication.mdx | 592 ++++++++++++++++++ .../ha-commands-reference.mdx | 183 +++++- .../how-high-availability-works.mdx | 105 +++- ...rying-the-cluster-in-high-availability.mdx | 42 +- .../auth-system-integrations.mdx | 18 + .../query-privileges.mdx | 31 +- .../role-based-access-control.mdx | 17 +- .../enabling-memgraph-enterprise.mdx | 6 + pages/release-notes.mdx | 34 + 11 files changed, 1011 insertions(+), 23 deletions(-) create mode 100644 pages/clustering/high-availability/coordinator-authentication.mdx diff --git a/pages/clustering/high-availability.mdx b/pages/clustering/high-availability.mdx index be6a01e31..19f83d8e3 100644 --- a/pages/clustering/high-availability.mdx +++ b/pages/clustering/high-availability.mdx @@ -49,6 +49,11 @@ recommended configuration patterns. Recommended practices for running a robust, reliable, and well-observed HA deployment. +### [Coordinator authentication](/clustering/high-availability/coordinator-authentication) + +Secure the cluster's control plane with single sign-on, Raft-replicated +coordinator roles, and the `COORDINATOR_READ` / `COORDINATOR_WRITE` privileges. + ### [HA commands reference guide](/clustering/high-availability/ha-commands-reference) A complete reference of all commands for managing coordinators, registering diff --git a/pages/clustering/high-availability/_meta.ts b/pages/clustering/high-availability/_meta.ts index f09ece7ce..23e5c8ca2 100644 --- a/pages/clustering/high-availability/_meta.ts +++ b/pages/clustering/high-availability/_meta.ts @@ -1,6 +1,7 @@ export default { "how-high-availability-works": "Under the hood", "querying-the-cluster-in-high-availability": "Querying the cluster in HA", + "coordinator-authentication": "Coordinator authentication", "setup-ha-cluster-docker": "Set up HA cluster with Docker", "setup-ha-cluster-docker-compose": "Set up HA cluster with Docker Compose", "setup-ha-cluster-k8s": "Set up HA cluster with K8s", diff --git a/pages/clustering/high-availability/coordinator-authentication.mdx b/pages/clustering/high-availability/coordinator-authentication.mdx new file mode 100644 index 000000000..9b0907c8f --- /dev/null +++ b/pages/clustering/high-availability/coordinator-authentication.mdx @@ -0,0 +1,592 @@ +--- +title: Coordinator authentication and authorization +description: Learn how to secure Memgraph high availability coordinators with single sign-on, Raft-replicated roles and the COORDINATOR_READ and COORDINATOR_WRITE privileges. +--- + +import { Callout } from 'nextra/components' +import { Steps } from 'nextra/components' +import {CommunityLinks} from '/components/social-card/CommunityLinks' + +# Coordinator authentication and authorization Enterprise + +Coordinators are the control plane of a [high availability +cluster](/clustering/high-availability): they register and unregister data +instances, promote and demote MAIN, hand out the routing table, and change +cluster-wide settings. From Memgraph 3.13, that control plane can be protected +with [single sign-on (SSO)](/database-management/authentication-and-authorization/auth-system-integrations#single-sign-on) +against your corporate identity provider (IdP), backed by a small set of +Raft-replicated roles. + + +SSO authentication on coordinators, coordinator role management, privilege +grants and privilege enforcement are **Memgraph Enterprise** features and +require a valid license. Without a valid license, coordinators keep the +pre-3.13 behavior: username/password connections are accepted as a passthrough +with full access. + + +Before continuing, read [how high availability +works](/clustering/high-availability/how-high-availability-works) and [querying +the cluster in high +availability](/clustering/high-availability/querying-the-cluster-in-high-availability). + +## How coordinator auth differs from data instances + +Coordinators do **not** store users. There is no auth key-value store on a +coordinator, no `CREATE USER`, no passwords, and no fine-grained access control. +The only authorization state a coordinator keeps is a list of **roles**, each +carrying a coordinator privilege mask. + +| | Data instance | Coordinator | +|---|---|---| +| Users | Stored in the auth store | Not supported | +| Roles | Stored in the auth store | Stored in the **Raft-replicated cluster state** | +| Privileges | Full privilege set + fine-grained access control | Exactly two: `COORDINATOR_READ`, `COORDINATOR_WRITE` | +| Basic auth | Username and password are validated | Passthrough — credentials are ignored (see [below](#basic-authentication-passthrough)) | +| SSO | Supported (OIDC, SAML, Kerberos) | Supported (OIDC, SAML, Kerberos) | + +Because roles live in the Raft log, they survive coordinator restarts, are +replicated to every coordinator, are reconstructed by a follower that rejoins +after being down, and survive leader failover. + + +**Breaking change in Memgraph 3.13:** the `COORDINATOR` privilege has been +removed. It never gated any operation. It is no longer accepted in `GRANT` / +`DENY` / `REVOKE` statements and is no longer reported by `SHOW PRIVILEGES`. A +stale `COORDINATOR` grant in an existing deployment is simply never reported and +never checked — no migration is required. Coordinator access is now controlled +by the new `COORDINATOR_READ` and `COORDINATOR_WRITE` privileges described +below, which are granted **on the coordinators themselves**, not on data +instances. + + +## Coordinator privileges + +Coordinators enforce exactly two privileges: + +| Privilege | Grants | +|---|---| +| `COORDINATOR_READ` | Reading the routing table and all read-only introspection queries. | +| `COORDINATOR_WRITE` | Every query runnable on a coordinator. `COORDINATOR_WRITE` is a **superset** of `COORDINATOR_READ`. | + +These names were chosen because bare `READ` and `WRITE` already exist as +data-instance fine-grained privileges. They are meaningful **only on +coordinators** and are deliberately excluded from the data-instance privilege +set, so `GRANT ALL PRIVILEGES` on a data instance does not grant them. + +A session's effective privilege is the **union** of the masks of all its roles. +A role with no grant confers nothing. + +### Which privilege each query requires + +Read-only introspection requires `COORDINATOR_READ`; every mutating or +administrative query requires `COORDINATOR_WRITE`. A `COORDINATOR_WRITE` grant +satisfies a `COORDINATOR_READ` requirement, but not the other way round. + +| Query | Required privilege | +|---|---| +| Routing table (Bolt `ROUTE` message) | `COORDINATOR_READ` | +| [`SHOW INSTANCE`](/clustering/high-availability/ha-commands-reference#show-instance) | `COORDINATOR_READ` | +| [`SHOW INSTANCES`](/clustering/high-availability/ha-commands-reference#show-instances) | `COORDINATOR_READ` | +| [`SHOW COORDINATOR SETTINGS`](/clustering/high-availability/ha-commands-reference#coordinator-runtime-settings) | `COORDINATOR_READ` | +| [`SHOW REPLICATION LAG`](/clustering/high-availability/ha-commands-reference#show-replication-lag) | `COORDINATOR_READ` | +| `SHOW ROLES` | `COORDINATOR_READ` | +| `SHOW PRIVILEGES FOR ROLE ` | `COORDINATOR_READ` | +| `SHOW CONFIG`, `SHOW SETTING`, system info queries | `COORDINATOR_READ` | +| `SHOW CURRENT USER`, `SHOW CURRENT ROLE` | **None** (self-service, see [below](#self-service-identity-queries)) | +| [`REGISTER INSTANCE`](/clustering/high-availability/ha-commands-reference#register-instance) / [`UNREGISTER INSTANCE`](/clustering/high-availability/ha-commands-reference#unregister-instance) | `COORDINATOR_WRITE` | +| [`SET INSTANCE ... TO MAIN`](/clustering/high-availability/ha-commands-reference#set-instance--to-main) / [`DEMOTE INSTANCE`](/clustering/high-availability/ha-commands-reference#demote-instance) | `COORDINATOR_WRITE` | +| [`ADD COORDINATOR`](/clustering/high-availability/ha-commands-reference#add-coordinator) / [`REMOVE COORDINATOR`](/clustering/high-availability/ha-commands-reference#remove-coordinator) | `COORDINATOR_WRITE` | +| [`UPDATE CONFIG`](/clustering/high-availability/ha-commands-reference#update-config) | `COORDINATOR_WRITE` | +| [`YIELD LEADERSHIP`](/clustering/high-availability/ha-commands-reference#yield-leadership) | `COORDINATOR_WRITE` | +| [`SET COORDINATOR SETTING`](/clustering/high-availability/ha-commands-reference#coordinator-runtime-settings) | `COORDINATOR_WRITE` | +| [`FORCE RESET CLUSTER STATE`](/clustering/high-availability/ha-commands-reference#force-reset-cluster-state) | `COORDINATOR_WRITE` | +| `SET SETTING` | `COORDINATOR_WRITE` | +| [`RELOAD BOLT_SERVER TLS` / `RELOAD INTRA_CLUSTER TLS`](/database-management/ssl-encryption#reload-ssl-certificates-at-runtime) | `COORDINATOR_WRITE` | +| `CREATE ROLE`, `DROP ROLE`, `GRANT`, `REVOKE` | `COORDINATOR_WRITE` | + +Anything not recognized fails closed and requires `COORDINATOR_WRITE`. + +## Authentication modes + +A coordinator accepts exactly two kinds of Bolt connection: **basic/none** and +an **SSO scheme listed in `--auth-module-mappings`**. Any other scheme is +rejected with: + +``` +The "" authentication scheme isn't supported on this coordinator; +connect with basic auth or an SSO scheme listed in the auth-module-mappings flag. +``` + +### Basic authentication passthrough + +When SSO is not in effect, connecting with a username and password (or with no +auth at all) **succeeds and the credentials are ignored**. The session gets full +`COORDINATOR_WRITE` access. This is the pre-3.13 behavior, it requires no +license, and it keeps existing admin tooling working unchanged. + +Basic/none authentication is **denied** only when **all three** of the following +hold: + +1. SSO is configured — `--auth-module-mappings` is non-empty. +2. The enterprise license is valid. +3. The committed role set contains at least one role holding + `COORDINATOR_WRITE`. + +In that case the connection is rejected with: + +``` +Basic authentication is disabled on this coordinator because SSO is configured; +connect with an SSO scheme listed in the auth-module-mappings flag. +``` + + +**Anybody can log in until a `COORDINATOR_WRITE` role exists.** Condition 3 is +what makes coordinator SSO self-bootstrapping. On a coordinator that starts with +`--auth-module-mappings` set but an empty role set, SSO cannot yet grant a +privileged session to anybody — so basic auth stays open, and you use it to +create the first role and grant it `COORDINATOR_WRITE`. The moment that grant +commits to Raft, basic auth closes on the next login attempt and SSO takes over. +**No coordinator restart is required.** + +The same rule applies in reverse: if you drop or revoke the last +`COORDINATOR_WRITE` role on a live cluster, basic auth reopens rather than +leaving the cluster unadministrable. + + + +**Break-glass on license loss.** If the enterprise license is missing, expired +or invalid, SSO rejects every login. Condition 2 above means basic auth falls +back to the passthrough in exactly that case, so a license transition can never +lock every Bolt session out of a coordinator. Use that session to re-install the +license over Bolt: + +```cypher +SET DATABASE SETTING 'enterprise.license' TO 'License'; +SET DATABASE SETTING 'organization.name' TO 'Organization'; +``` + +The license check for this decision is the full, non-cached check — a license +that expires by date takes effect immediately rather than at the next cache +refresh. + + +### A follower without quorum cannot be logged into + +Both the basic-auth decision and the SSO role check need the **leader's** +committed role set, and both are **fail-closed**: when the leader cannot be +reached, the login is rejected rather than validated against possibly-stale +local replicated state, which could still list a dropped role or an +already-revoked privilege mask. + +So on a coordinator that has lost quorum (it is a follower, no leader is +elected, or the leader is unreachable) and has SSO configured with a valid +license: + +- **SSO logins are rejected** with: + + ``` + SSO authentication failed: the coordinator leader is unreachable, so roles + can't be validated. Retry once a leader is elected. + ``` + +- **Basic/none logins are also rejected.** An unknown role set is not treated as + "no writable role", so the break-glass path does not open during a transient + leader outage. + +This is intentional and temporary: SSO is unavailable in that window anyway, and +access returns as soon as a leader is elected. If SSO is **not** configured, the +basic-auth passthrough never contacts the leader, so it keeps working on a +partitioned follower. + +### SSO authentication + +For a scheme present in `--auth-module-mappings`, the coordinator runs the +corresponding auth module and genuinely authenticates the connection. The same +[built-in and custom auth +modules](/database-management/authentication-and-authorization/auth-system-integrations) +used on data instances work here, and `MEMGRAPH_SSO_*` environment variables are +inherited by the module subprocess exactly as they are on data instances — there +is no separate coordinator-side SSO configuration. + +The login is accepted only when **all** of the following hold: + +1. The module authenticates the identity (valid, unexpired IdP token). +2. The module returns at least one role. +3. **Every** role the module returns exists in the coordinator's committed role + set. A multi-role response succeeds only when all of its roles exist. +4. The union of those roles' masks grants at least `COORDINATOR_READ`. + + +**A role without privileges cannot be used to log in.** If the roles all exist +but none of them has been granted `COORDINATOR_READ` or `COORDINATOR_WRITE`, the +connection is **rejected at login** rather than admitted as a session that would +be denied every query — including the routing table. Grant a privilege to the +role before mapping identities onto it. + + +Each rejection reason has its own message, so an operator rolling SSO out can +tell a bad token apart from a misconfigured role mapping: + +| Situation | Error returned to the client | +|---|---| +| Invalid/expired token, module failure, or missing license | `SSO authentication failed: the identity provider token was rejected, the auth module failed, or the enterprise license is missing.` | +| Module returned no roles | `SSO authentication failed: the identity provider returned no roles for this identity. Map the identity's group to a coordinator role.` | +| A returned role does not exist on the coordinator | `SSO authentication failed: the identity provider returned a role that doesn't exist on this coordinator. Create it with CREATE ROLE, or fix the identity provider mapping.` | +| Roles exist but carry no privilege | `SSO authentication failed: this identity's role(s) exist but carry no coordinator privilege. Grant COORDINATOR_READ or COORDINATOR_WRITE to one of them.` | +| Leader unreachable | `SSO authentication failed: the coordinator leader is unreachable, so roles can't be validated. Retry once a leader is elected.` | + +The offending role name is written to the coordinator log, **not** returned to +the client, so a rejected login cannot be used to enumerate the coordinator's +role set. + +The username the module reports is recorded as the session principal and is used +for [audit logging](/database-management/logs) and `SHOW CURRENT USER`. A module +that omits the username still logs in — the coordinator authorizes by role — but +its queries cannot be attributed to a person, and a warning is logged once at +login. + +## Managing coordinator roles and privileges + +All role and privilege queries are documented in the [HA reference +commands](/clustering/high-availability/ha-commands-reference#coordinator-role-and-privilege-management) +guide. In short: + +```cypher +CREATE ROLE ops; +CREATE ROLE IF NOT EXISTS ops; +DROP ROLE ops; +SHOW ROLES; + +GRANT COORDINATOR_READ TO ops; +GRANT COORDINATOR_WRITE TO ops; +GRANT ALL PRIVILEGES TO ops; -- grants both coordinator privileges +REVOKE COORDINATOR_WRITE FROM ops; +REVOKE ALL PRIVILEGES FROM ops; -- removes both + +SHOW PRIVILEGES FOR ROLE ops; +``` + +All of these can be run on **any** coordinator: on a follower they are +transparently forwarded to the leader. Writes are committed through the Raft +log; `SHOW ROLES` and `SHOW PRIVILEGES FOR ROLE` are strong reads served by the +leader. + +### Self-service identity queries + +`SHOW CURRENT USER` and `SHOW CURRENT ROLE` are exempt from the privilege check +and from the license gate — they only reveal the session's own identity, so even +a session whose roles were revoked mid-flight can still inspect who it is. + +- `SHOW CURRENT USER` returns the principal the identity provider authenticated. + It is purely session-local and works even when the leader is unreachable. A + basic-auth passthrough session authenticated no principal and returns `null`. +- `SHOW CURRENT ROLE` returns the session's roles **filtered against the + leader's committed role set**, so it stops naming a role that `DROP ROLE` + already removed. A basic-auth passthrough session has no roles and returns + `null`. + +### Auth queries rejected on coordinators + +Everything outside the small surface above is rejected with: + +``` +Coordinator can run only coordinator queries! +``` + +That includes: + +- User management: `CREATE USER`, `SET PASSWORD`, `SHOW USERS`, `SET ROLE`, + `GRANT ROLE`. +- `DENY` in **any** form. +- `GRANT` / `REVOKE` targeting a `USER` (`GRANT COORDINATOR_READ TO USER foo`). +- Privilege lists containing any non-coordinator privilege + (`GRANT MATCH TO ops`). +- [Fine-grained access + control](/database-management/authentication-and-authorization/role-based-access-control#fine-grained-access-control) + — `GRANT ... ON NODES ...` / `ON EDGES ...` — coordinators have no graph. +- Property permissions. +- [Multi-tenancy](/database-management/multi-tenancy) database access: + `GRANT DATABASE`, `REVOKE DATABASE`, `SET MAIN DATABASE`. +- `SHOW PRIVILEGES FOR USER `. +- `SHOW PRIVILEGES FOR ROLE ` with a trailing `ON MAIN`, `ON CURRENT` or + `ON DATABASE ` clause — coordinators have no databases. + +## Privileges are re-checked on every query + +An SSO session does **not** cache the privilege mask it was given at login. On +**every** query — and on every routing-table request — the coordinator +re-derives the session's effective mask from the **leader's** committed role set: +if this coordinator is the ready leader it reads locally, otherwise it sends a +`GetRolesRpc` to the leader. + +This has three consequences worth planning for: + +- **`REVOKE` and `DROP ROLE` take effect immediately**, without the client + reconnecting. Long-lived connections — driver routing pools, open admin shells + — are downgraded on their very next query. A session whose roles were all + dropped keeps its connection but is denied every privileged query. +- **A leader outage denies queries on SSO sessions.** With no readable role set + the effective mask is empty (fail-closed), so queries fail until a leader is + elected. Retry once `SHOW INSTANCES` reports a leader again. +- **Basic-auth passthrough sessions are unaffected.** They carry no roles, so + they keep their login-time full `COORDINATOR_WRITE` mask and never contact the + leader for a privilege check. + +Denied queries fail with: + +``` +You don't have the required privilege to run this query on the coordinator! +``` + +and a denied routing-table request fails with: + +``` +You don't have permission to read the routing table on the coordinator! +``` + +The routing-table denial is reported as a non-retryable client error, so drivers +do not retry it as if it were a transient failure. + +## Bolt+routing with SSO + + +**A `neo4j://` routing connection works only if the same roles exist on both the +coordinators and the data instances.** + + +[Bolt+routing](/clustering/high-availability/querying-the-cluster-in-high-availability) +is entirely client-side, and the driver reuses **one set of credentials for both +legs** of the connection. With SSO in the picture, a single `neo4j://` session +therefore performs two independent authentications: + + + +{

The driver authenticates against a coordinator

} + +It sends the SSO scheme and IdP token to a coordinator and issues a `ROUTE` +message. The coordinator runs the auth module, requires every returned role to +exist **in the Raft-replicated coordinator role set**, and requires the union of +their masks to grant at least `COORDINATOR_READ` — otherwise the routing table +request is denied. + +{

The driver authenticates against a data instance

} + +Using the routing table, the driver opens a connection to MAIN or a REPLICA with +the **same scheme and the same token**. The data instance runs its own auth +module and requires every returned role to exist **in its auth store**, with +whatever data privileges (`MATCH`, `CREATE`, …) the query needs. + +
+ +For that to work end to end: + +| Requirement | Why | +|---|---| +| The **same SSO scheme** is listed in `--auth-module-mappings` on coordinators *and* on every data instance | The driver sends one scheme to both; a scheme absent from a node's mappings is rejected there. | +| The **same role names** the IdP returns exist on coordinators *and* on data instances | Each side validates the returned roles against its own role store, and any missing role rejects the whole login on that side. | +| Those roles hold `COORDINATOR_READ` (or `COORDINATOR_WRITE`) **on the coordinators** | Otherwise the `ROUTE` message is denied and the driver never obtains a routing table. | +| Those roles hold the needed **data privileges on the data instances** | The coordinator privileges are not visible to, and mean nothing on, a data instance. | + +The privilege *values* are necessarily different on the two sides — coordinators +know only `COORDINATOR_READ` / `COORDINATOR_WRITE`, data instances know only the +data privilege set — but the **role names must match**. A typical setup mirrors +each IdP group into a role of the same name on both sides: + +```cypher +-- On any coordinator +CREATE ROLE analyst; +GRANT COORDINATOR_READ TO analyst; + +CREATE ROLE dba; +GRANT ALL PRIVILEGES TO dba; -- COORDINATOR_READ + COORDINATOR_WRITE +``` + +```cypher +-- On the MAIN data instance (replicated to REPLICAs) +CREATE ROLE analyst; +GRANT MATCH TO analyst; + +CREATE ROLE dba; +GRANT ALL PRIVILEGES TO dba; -- the full data-instance privilege set +``` + + +A role that exists on the data instances but not on the coordinators produces a +confusing failure mode: direct `bolt://` connections to MAIN work, but every +`neo4j://` routing connection fails at the coordinator. Check `SHOW ROLES` on a +coordinator and `SHOW ROLES` on MAIN and reconcile the two lists. + + +## Rolling SSO out + +The bootstrap order differs between coordinators and data instances, and getting +it wrong is the most common way to lock yourself out. + +### On coordinators — no restart needed + +Coordinators can be started with `--auth-module-mappings` from the very +beginning. Because basic auth stays open until a `COORDINATOR_WRITE` role +exists, you can create the roles over Bolt on the running cluster. + + + +{

Start the coordinators with the SSO mapping

} + +``` +--auth-module-mappings=oidc-entra-id +``` + +Set the `MEMGRAPH_SSO_*` environment variables the module needs, exactly as you +would on a data instance. + +{

Connect with basic auth

} + +No `COORDINATOR_WRITE` role exists yet, so username/password (or no credentials +at all) is still accepted with full access: + +``` +mgconsole --host --port 7687 +``` + +{

Create the roles and grant privileges

} + +```cypher +CREATE ROLE dba; +GRANT ALL PRIVILEGES TO dba; + +CREATE ROLE analyst; +GRANT COORDINATOR_READ TO analyst; +``` + +The role names must match what your IdP returns — see [role +mapping](/database-management/authentication-and-authorization/auth-system-integrations#role-mapping). + +{

SSO is now enforced

} + +As soon as `GRANT ALL PRIVILEGES TO dba` commits to Raft, all three deny +conditions hold and the **next** basic-auth login attempt is rejected. Existing +basic-auth sessions keep their full mask until they disconnect. Verify with: + +```cypher +SHOW ROLES; +SHOW PRIVILEGES FOR ROLE dba; +``` + +
+ +### On data instances — restart required + +Data instances have no equivalent escape hatch. Their SSO path validates the +IdP's roles against the auth store, and a role that does not exist means the +login fails. If you enable the module before the roles exist, SSO users cannot +log in and — when the mapped scheme is `basic` (LDAP) — username/password +authentication is delegated to the module too, so you may have no way in at all +to create them. + +The safe order is therefore: + + + +{

Start the data instance *without* `--auth-module-mappings`

} + +{

Log in and create the roles

} + +```cypher +CREATE ROLE dba; +GRANT ALL PRIVILEGES TO dba; + +CREATE ROLE analyst; +GRANT MATCH TO analyst; +``` + +{

Restart the data instance with `--auth-module-mappings` set

} + +SSO logins now find their roles and succeed. + +
+ + +In containerized deployments you can collapse this into a single start by +creating the roles with +[`--init-file`](/database-management/authentication-and-authorization/auth-system-integrations#docker-deployment-note), +which runs a Cypher script before the database begins serving connections. That +avoids the stop-and-restart cycle entirely. + + + +Do the coordinator side and the data-instance side with the **same role names**, +or [Bolt+routing](#boltrouting-with-sso) connections will fail even though +direct connections to each node work. + + +## Rolling upgrades + +The new role and privilege queries are carried by new coordinator-to-coordinator +RPCs. There is no RPC version negotiation. During a rolling upgrade, if a +new follower forwards a role or privilege query to a leader that has not been +upgraded yet, the query **fails with an error** rather than crashing the +coordinator: + +``` +Query forwarded to the leader but it failed to process the request! +Check the logs on the leader to find out what happened. +``` + +Complete the upgrade of all coordinators before managing roles, or run the role +queries directly against an upgraded leader. + +The Raft cluster state itself is version-safe in both directions: an older +coordinator ignores the unknown roles key, and a newer coordinator reading an +older log or snapshot sees an empty role set. No log store version bump is +involved. + +## Timeouts + +Role and privilege queries — like all forwarded coordinator queries — run on the +caller's Bolt session thread, so they carry explicit RPC timeouts to prevent a +session blocking forever against a reachable-but-stuck leader. See [RPC +timeouts](/clustering/high-availability/how-high-availability-works#rpc-timeouts) +for the full table. The values relevant to authentication are: + +| RPC | Timeout | Used by | +|---|---|---| +| `GetRolesReq` | 10s | SSO login role validation, the per-query privilege re-check, `SHOW ROLES`, `SHOW CURRENT ROLE` | +| `GetRolePrivilegesReq` | 10s | `SHOW PRIVILEGES FOR ROLE` | +| `CreateRoleReq` / `DropRoleReq` | 10s | `CREATE ROLE`, `DROP ROLE` | +| `GrantPrivilegeReq` / `RevokePrivilegeReq` | 10s | `GRANT`, `REVOKE` | + +Each of these budgets covers a Raft commit, which is itself capped at 3 seconds, +plus headroom. Hitting the timeout surfaces as a query error; retry the +operation. + +Independently of the RPC timeout, the auth module subprocess is bounded by +[`--auth-module-timeout-ms`](/database-management/authentication-and-authorization/auth-system-integrations#configuration-flags), +the same flag used on data instances. A module that exceeds it fails the login. + +## Limitations + +- **No users on coordinators.** Only the role set and each role's privilege mask + are persisted. There is no way to create a coordinator-local account. +- **No SSO auto-provisioning of roles.** Unlike some data-instance setups, an + SSO identity does not implicitly create `readonly` / `readwrite` / `admin` + roles on a coordinator. Roles must be created explicitly with `CREATE ROLE`. +- **Only two privileges.** The fine-grained data-instance privilege set is not + modeled on coordinators. +- **Role names** must match the + [`--auth-user-or-role-name-regex`](/database-management/configuration) pattern, + the same as on data instances. + +## Troubleshooting + +| Symptom | Likely cause | +|---|---| +| Basic auth suddenly rejected after a `GRANT` | Expected — a `COORDINATOR_WRITE` role now exists, so SSO is enforced. Connect with an SSO scheme. | +| Basic auth unexpectedly accepted while SSO is configured | Either the license is invalid, or no role holds `COORDINATOR_WRITE`. Check `SHOW PRIVILEGES FOR ROLE` and the license status. | +| Every login rejected on one coordinator | That coordinator cannot reach a leader. Check `SHOW INSTANCES` from another coordinator and wait for the election to finish. | +| SSO login rejected with "role that doesn't exist" | `CREATE ROLE` on the coordinator, or fix the IdP group mapping. Check `SHOW ROLES`. | +| SSO login rejected with "carry no coordinator privilege" | `GRANT COORDINATOR_READ` or `GRANT COORDINATOR_WRITE` to the role. | +| `neo4j://` fails but `bolt://` to MAIN works | The role exists on the data instances but not on the coordinators, or it lacks `COORDINATOR_READ`. | +| A session was working and now every query is denied | Its roles were revoked or dropped — privileges are re-checked on every query. Reconnect after fixing the grant. | + + diff --git a/pages/clustering/high-availability/ha-commands-reference.mdx b/pages/clustering/high-availability/ha-commands-reference.mdx index 40afbf51d..5f76a92ff 100644 --- a/pages/clustering/high-availability/ha-commands-reference.mdx +++ b/pages/clustering/high-availability/ha-commands-reference.mdx @@ -28,6 +28,17 @@ LEADERSHIP`](#yield-leadership), which must be run directly on the current leader. + +From Memgraph 3.13, coordinators can enforce privileges on these queries. Every +query on this page requires either `COORDINATOR_READ` (read-only introspection) +or `COORDINATOR_WRITE` (everything mutating). A session that connected with +basic auth carries full `COORDINATOR_WRITE`, so nothing changes unless you +enable [SSO on coordinators](/clustering/high-availability/coordinator-authentication). +See the [privilege +reference](/clustering/high-availability/coordinator-authentication#which-privilege-each-query-requires) +for the per-query mapping. + + ### `ADD COORDINATOR` Adds a coordinator to the cluster. @@ -332,7 +343,9 @@ informational notification that the request was submitted. - Failover of data instances is not triggered, but the new leader recomputes cluster state, so a cluster that was already missing a MAIN can fail over as part of the leadership change. -- No privilege is required to run this query on the coordinators. +- Requires `COORDINATOR_WRITE`. A basic-auth session carries it implicitly; an + [SSO session](/clustering/high-availability/coordinator-authentication) needs + a role that has been granted it. {

Typical use cases

} @@ -553,7 +566,11 @@ survives coordinator restarts and leader re-elections, and is honored across failovers: a newly promoted MAIN comes up read-only when the cluster is in read-only mode, instead of silently accepting writes. -No privilege is required to run this query on the coordinators. +`SET COORDINATOR SETTING` requires `COORDINATOR_WRITE` and `SHOW COORDINATOR +SETTINGS` requires `COORDINATOR_READ`. A basic-auth session carries both +implicitly; an [SSO +session](/clustering/high-availability/coordinator-authentication) needs a role +that has been granted them. Enabling read-only mode blocks **all write sources** on the MAIN — user Cypher @@ -575,10 +592,170 @@ cluster self-heals to the requested state. +## Coordinator role and privilege management + + +These queries are **Memgraph Enterprise** features and require a valid license. +They exist so that [SSO +identities](/clustering/high-availability/coordinator-authentication) have +something to map onto. Coordinators have no users — only roles. + + +Coordinator roles are stored in the **Raft-replicated cluster state**, not in +the auth store, so they survive restarts, follower catch-up and leader failover. +Like the cluster registration queries, all of these can be run on any +coordinator: writes are transparently forwarded to the leader and committed +through the Raft log, and `SHOW ROLES` / `SHOW PRIVILEGES FOR ROLE` are strong +reads served by the leader. + +### `CREATE ROLE` + +Creates a coordinator role. New roles start with **no** privileges. + +```cypher +CREATE ROLE ifNotExists? roleName; +``` + +{

Behavior & implications

} + +- Errors if the role already exists, unless `IF NOT EXISTS` is given. +- The role name must match the `--auth-user-or-role-name-regex` pattern, + otherwise the query fails with `Invalid role name ''.` +- Requires `COORDINATOR_WRITE`. + +{

Example

} + +```cypher +CREATE ROLE dba; +CREATE ROLE IF NOT EXISTS analyst; +``` + +### `DROP ROLE` + +Removes a coordinator role. + +```cypher +DROP ROLE roleName; +``` + +{

Behavior & implications

} + +- Errors with `Role '' doesn't exist.` if the role is not present. +- Takes effect on **already-connected sessions immediately** — privileges are + re-derived from the committed role set on every query, so a session that + authenticated with the dropped role is denied its next privileged query + without needing to reconnect. +- Requires `COORDINATOR_WRITE`. + +{

Example

} + +```cypher +DROP ROLE analyst; +``` + +### `SHOW ROLES` + +Lists the coordinator roles. Returns one `role` column, name only. + +```cypher +SHOW ROLES; +``` + +{

Behavior & implications

} + +- Strong read served by the leader. If no leader can be reached, the query fails + rather than returning possibly-stale local state. +- Requires `COORDINATOR_READ`. + +### `GRANT` / `REVOKE` coordinator privileges + +Grants or revokes a coordinator privilege on a role. Coordinators support +exactly two privileges: `COORDINATOR_READ` and `COORDINATOR_WRITE`, where +`COORDINATOR_WRITE` is a superset of `COORDINATOR_READ`. + +```cypher +GRANT ( ALL PRIVILEGES | COORDINATOR_READ | COORDINATOR_WRITE [, ...] ) TO ROLE? roleName; +REVOKE ( ALL PRIVILEGES | COORDINATOR_READ | COORDINATOR_WRITE [, ...] ) FROM ROLE? roleName; +``` + +{

Behavior & implications

} + +- `GRANT ALL PRIVILEGES` grants **both** coordinator privileges; + `REVOKE ALL PRIVILEGES` removes both. +- Errors with `Role '' doesn't exist.` if the role is not present. +- Only `COORDINATOR_READ` and `COORDINATOR_WRITE` may appear in the privilege + list. Any other privilege, `DENY` in any form, a `USER` target, fine-grained + access control (`ON NODES` / `ON EDGES`), property permissions and + `GRANT DATABASE` are all rejected on a coordinator. +- Like `DROP ROLE`, a `REVOKE` applies to already-connected sessions on their + next query. +- Requires `COORDINATOR_WRITE`. + +{

Example

} + +```cypher +GRANT ALL PRIVILEGES TO dba; +GRANT COORDINATOR_READ TO analyst; +REVOKE COORDINATOR_WRITE FROM analyst; +``` + +### `SHOW PRIVILEGES FOR ROLE` + +Reports the privileges granted to a coordinator role, one per row. + +```cypher +SHOW PRIVILEGES FOR ROLE? roleName; +``` + +{

Behavior & implications

} + +- A role with no grants returns no rows. +- The trailing `ON MAIN | CURRENT | DATABASE ` clause is **rejected** — + coordinators have no databases. +- `SHOW PRIVILEGES FOR USER ` is rejected — coordinators have no users. +- Strong read served by the leader. +- Requires `COORDINATOR_READ`. + +{

Example

} + +```cypher +SHOW PRIVILEGES FOR ROLE dba; +``` + +```plaintext ++---------------------+ +| privilege | ++---------------------+ +| COORDINATOR_READ | +| COORDINATOR_WRITE | ++---------------------+ +``` + +### `SHOW CURRENT USER` and `SHOW CURRENT ROLE` + +Report the identity of the current session. + +```cypher +SHOW CURRENT USER; +SHOW CURRENT ROLE; +``` + +{

Behavior & implications

} + +- **No privilege and no license are required** — these are self-service queries + that reveal only the session's own identity. +- `SHOW CURRENT USER` returns the principal the SSO module reported. It is + session-local and works even when the leader is unreachable. A basic-auth + passthrough session returns `null`. +- `SHOW CURRENT ROLE` returns the session's roles filtered against the leader's + committed role set, so a dropped role stops being reported. A basic-auth + passthrough session has no roles and returns `null`. + ## Error handling If a Raft log commit fails for any cluster operation (register, unregister, -promote, demote, add coordinator), the error message will indicate: +promote, demote, add coordinator, role or privilege change), the error message +will indicate: > Writing to Raft log failed. Please retry the operation. diff --git a/pages/clustering/high-availability/how-high-availability-works.mdx b/pages/clustering/high-availability/how-high-availability-works.mdx index 0773a4442..782f53cd4 100644 --- a/pages/clustering/high-availability/how-high-availability-works.mdx +++ b/pages/clustering/high-availability/how-high-availability-works.mdx @@ -255,24 +255,109 @@ in the cluster to ensure high availability, with timeouts. | RPC message request | source | target | timeout | |--------------------------|-------------|----------------| -----------------| -| `ShowInstancesReq` | Coordinator | Coordinator | | -| `DemoteMainToReplicaReq` | Coordinator | Data instance | | -| `PromoteToMainReq` | Coordinator | Data instance | | -| `RegisterReplicaOnMainReq` | Coordinator | Data instance | | -| `UnregisterReplicaReq` | Coordinator | Data instance | | -| `EnableWritingOnMainReq` | Coordinator | Data instance | deprecated | -| `GetDatabaseHistoriesReq` | Coordinator | Data instance | | +| `ShowInstancesReq` | Coordinator | Coordinator | 10s | +| `DemoteMainToReplicaReq` | Coordinator | Data instance | 10s | +| `PromoteToMainReq` | Coordinator | Data instance | 10s | +| `RegisterReplicaOnMainReq` | Coordinator | Data instance | 10s | +| `UnregisterReplicaReq` | Coordinator | Data instance | 10s | +| `ReplicationLagReq` | Coordinator | Data instance | 5s | +| `GetDatabaseHistoriesReq` | Coordinator | Data instance | 10s | | `StateCheckReq` | Coordinator | Data instance | 5s | -| `SwapMainUUIDReq` | Coordinator | Data instance | | +| `SwapMainUUIDReq` | Coordinator | Data instance | 10s | +| `UpdateDataInstanceConfigReq` | Coordinator | Data instance | 10s | | `FrequentHeartbeatReq` | Main | Replica | 5s | -| `HeartbeatReq` | Main | Replica | | -| `SystemRecoveryReq` | Main | Replica | 5s | +| `HeartbeatReq` | Main | Replica | 10s | +| `SystemRecoveryReq` | Main | Replica | 30s | | `PrepareCommitRpc` | Main | Replica | proportional | | `FinalizeCommitReq` | Main | Replica | 10s | | `SnapshotRpc` | Main | Replica | proportional | | `WalFilesRpc` | Main | Replica | proportional | | `CurrentWalRpc` | Main | Replica | proportional | + +`EnableWritingOnMainReq` was **removed in Memgraph 3.13**. It was never sent — +writing on a newly promoted MAIN is enabled through the `writing_enabled` flag +carried inside `PromoteToMainRpc`. Its Prometheus counters were removed along +with it. + + +{
Follower-to-leader forwarding timeouts
} + +Cluster management queries can be run on any coordinator; a follower forwards +them to the leader over RPC. From Memgraph 3.13, each of these RPCs has an +explicit timeout. They run on the caller's **Bolt session thread**, so without +one, a session would block forever against a leader that is reachable but stuck. + +The four instance operations must outlast the work they trigger on the leader, +or a follower would report failure for an operation the leader has already +committed to Raft. Their budgets are the sum of that work plus headroom, where a +Raft commit is capped at 3 seconds and each RPC from the leader to a data +instance is capped by its entry in the table above. + +| RPC message request | source | target | timeout | Budget breakdown | +|--------------------------|-------------|-------------|---------|------------------| +| `RegisterInstanceReq` | Coordinator | Coordinator | 30s | Raft commit + demote the new replica + register it | +| `UnregisterInstanceReq` | Coordinator | Coordinator | 20s | Raft commit + one RPC to the current MAIN | +| `DemoteInstanceReq` | Coordinator | Coordinator | 20s | Raft commit + one RPC to the current MAIN | +| `SetInstanceToMainReq` | Coordinator | Coordinator | 60s | Raft commit + one `SwapMainUUID` per other instance + promote the new MAIN | +| `AddCoordinatorReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `RemoveCoordinatorReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `UpdateConfigReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `ForceResetReq` | Coordinator | Coordinator | 60s | Unbounded leader-side work — see the note below | +| `SetCoordinatorSettingReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `GetRoutingTableReq` | Coordinator | Coordinator | 10s | Read served by the leader | +| `CoordReplLagReq` | Coordinator | Coordinator | 10s | Read served by the leader | +| `CreateRoleReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `DropRoleReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `GrantPrivilegeReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `RevokePrivilegeReq` | Coordinator | Coordinator | 10s | Raft commit only | +| `GetRolesReq` | Coordinator | Coordinator | 10s | Read served by the leader | +| `GetRolePrivilegesReq` | Coordinator | Coordinator | 10s | Read served by the leader | + + +`SetInstanceToMainReq` sends one `SwapMainUUID` per other instance, so its cost +grows with the number of data instances. The 60s budget comfortably covers five +instances. Beyond that, a follower can time out before the leader answers — no +fixed value bounds it. Run `SET INSTANCE ... TO MAIN` directly on the leader in +very large clusters. + +`ForceResetReq` triggers a reconciliation that retries under a 1s–60s backoff +for as long as the coordinator stays leader, so the leader-side work has no +upper bound at all. The 60s budget only keeps a genuinely wedged leader from +blocking the session — hitting it does **not** mean the reset failed, and +[`FORCE RESET CLUSTER +STATE`](/clustering/high-availability/ha-commands-reference#force-reset-cluster-state) +is safe to re-run. + + +The role and privilege RPCs are used by [coordinator +authentication](/clustering/high-availability/coordinator-authentication): +`GetRolesReq` in particular is sent on **every query of an SSO session**, because +coordinator privileges are re-derived from the leader's committed role set +rather than cached at login. + +{
System transaction timeouts
} + +MAIN-to-REPLICA system-delta RPCs are sent while committing a system +transaction, so they must not block indefinitely either. From Memgraph 3.13 each +carries a **10 second** timeout; a timeout marks the REPLICA as `BEHIND` and +defers to system recovery. + +| RPC message request | source | target | timeout | +|---------------------|--------|---------|---------| +| `UpdateAuthDataReq` | Main | Replica | 10s | +| `DropAuthDataReq` | Main | Replica | 10s | +| `FinalizeSystemTxReq` | Main | Replica | 10s | +| `CreateDatabaseReq` | Main | Replica | 10s | +| `DropDatabaseReq` | Main | Replica | 10s | +| `SuspendDatabaseReq` | Main | Replica | 10s | +| `ResumeDatabaseReq` | Main | Replica | 10s | +| `RenameDatabaseReq` | Main | Replica | 10s | +| `TenantProfileReq` | Main | Replica | 10s | +| `SetParameterReq` | Main | Replica | 10s | +| `UnsetParameterReq` | Main | Replica | 10s | +| `DeleteAllParametersReq`| Main | Replica | 10s | + ## Intra-cluster TLS By default, the communication between instances in a high-availability cluster diff --git a/pages/clustering/high-availability/querying-the-cluster-in-high-availability.mdx b/pages/clustering/high-availability/querying-the-cluster-in-high-availability.mdx index 74eaa3b51..9daf11db6 100644 --- a/pages/clustering/high-availability/querying-the-cluster-in-high-availability.mdx +++ b/pages/clustering/high-availability/querying-the-cluster-in-high-availability.mdx @@ -172,21 +172,51 @@ When using the **bolt+routing protocol**, provide credentials for users that exist on the data instances. The authentication flow works as follows: 1. The client authenticates and connects to a **coordinator**. -2. The coordinator returns a routing table - no authentication occurs here. +2. The coordinator returns a routing table. 3. The client connects to the appropriate **data instance** using the **same credentials**. 4. The data instance performs authentication and executes the query. -This preserves a clean separation: coordinators route traffic, while data -instances manage users. - -1. You may connect to a coordinator via plain Bolt **without authentication**. -2. When using Bolt+routing, you **must** provide credentials - authentication is +1. By default, you may connect to a coordinator via plain Bolt **without + authentication** — username and password are accepted as a passthrough and + ignored. +2. When using Bolt+routing, you **must** provide credentials — authentication is performed on the data instances. +### Authenticating against coordinators + +From Memgraph 3.13, coordinators are no longer unconditionally open. They can +enforce [single sign-on and coordinator +privileges](/clustering/high-availability/coordinator-authentication), which +changes the flow above in two ways: + +- **Step 1 becomes a real authentication.** Once SSO is configured on the + coordinators, basic auth is refused and the client must present a valid IdP + token for a scheme listed in `--auth-module-mappings`. +- **Step 2 requires a privilege.** Serving the routing table requires + `COORDINATOR_READ`. A session whose roles carry no coordinator privilege is + denied the routing table with `You don't have permission to read the routing + table on the coordinator!` — reported as a non-retryable client error so + drivers do not retry it. + + + +Because the driver reuses **one set of credentials for both legs** of a routing +connection, a `neo4j://` session works only when the **same role names exist on +both the coordinators and the data instances**, and the same SSO scheme is +configured on both. The privileges attached to those roles differ by design — +coordinators know only `COORDINATOR_READ` / `COORDINATOR_WRITE`, data instances +know only the data privilege set — but the names must match. + +See [Bolt+routing with +SSO](/clustering/high-availability/coordinator-authentication#boltrouting-with-sso) +for the full setup. + + + diff --git a/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx b/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx index db2a1eb4c..a91170d5c 100644 --- a/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx +++ b/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx @@ -154,6 +154,24 @@ This approach ensures that all roles are created before the external authentication module is activated, allowing users to log in seamlessly across all supported authentication methods. +If you cannot use `--init-file`, the equivalent manual procedure is to start the +data instance **without** `--auth-module-mappings`, log in, create the roles and +grant their privileges, then restart with the flag set. + + +From Memgraph 3.13, [high availability +coordinators](/clustering/high-availability/coordinator-authentication) also +support SSO, using these same modules, schemes and `MEMGRAPH_SSO_*` environment +variables. Coordinators **do not** need this stop-and-restart cycle: basic +authentication stays open until a role holding `COORDINATOR_WRITE` exists, so +you can start them with `--auth-module-mappings` from the beginning and create +the roles over Bolt on the running cluster. + +Note that a `neo4j://` routing connection authenticates against a coordinator +*and* a data instance with the same credentials, so the **same role names must +exist on both**. + + ## Auth module architecture ### Communication protocol diff --git a/pages/database-management/authentication-and-authorization/query-privileges.mdx b/pages/database-management/authentication-and-authorization/query-privileges.mdx index 7fb7ab614..034e9885b 100644 --- a/pages/database-management/authentication-and-authorization/query-privileges.mdx +++ b/pages/database-management/authentication-and-authorization/query-privileges.mdx @@ -156,7 +156,7 @@ Memgraph's privilege system controls access to various database operations throu | `REPLICATION` operations | `REPLICATION` | Various replication commands. | | `SHOW REPLICATION ROLE` | `REPLICATION` | `SHOW REPLICATION ROLE` | | `SHOW REPLICAS` | `REPLICATION` | `SHOW REPLICAS` | -| `SHOW REPLICATION LAG` | `COORDINATOR` | `SHOW REPLICATION LAG` | +| `SHOW REPLICATION LAG` | `COORDINATOR_READ` | Coordinators only — see [Coordinator operations](#coordinator-operations). | ## Multi-database operations @@ -191,10 +191,35 @@ Memgraph's privilege system controls access to various database operations throu ## Coordinator operations +These privileges apply **only on [high availability +coordinators](/clustering/high-availability/coordinator-authentication)**. They +are granted to roles that live in the coordinators' Raft-replicated cluster +state, not in the data-instance auth store, and are not part of the +data-instance privilege set — `GRANT ALL PRIVILEGES` on a data instance does not +grant them. + +`COORDINATOR_WRITE` is a superset of `COORDINATOR_READ`: a `COORDINATOR_WRITE` +grant satisfies a `COORDINATOR_READ` requirement. A session that connected to a +coordinator with basic auth carries both implicitly. + | Query Type | Required Privileges | Example | |------------|-------------------|---------| -| `COORDINATOR` operations | `COORDINATOR` | Various coordinator commands. | -| `SHOW COORDINATOR SETTINGS` | `COORDINATOR` | `SHOW COORDINATOR SETTINGS` | +| Routing table (Bolt `ROUTE` message) | `COORDINATOR_READ` | Any `neo4j://` connection. | +| `SHOW INSTANCE` / `SHOW INSTANCES` | `COORDINATOR_READ` | `SHOW INSTANCES` | +| `SHOW COORDINATOR SETTINGS` | `COORDINATOR_READ` | `SHOW COORDINATOR SETTINGS` | +| `SHOW REPLICATION LAG` | `COORDINATOR_READ` | `SHOW REPLICATION LAG` | +| `SHOW ROLES` / `SHOW PRIVILEGES FOR ROLE` | `COORDINATOR_READ` | `SHOW PRIVILEGES FOR ROLE dba` | +| `SHOW CONFIG`, `SHOW SETTING`, system info queries | `COORDINATOR_READ` | `SHOW CONFIG` | +| `SHOW CURRENT USER` / `SHOW CURRENT ROLE` | **None** | Self-service identity queries. | +| Cluster management operations | `COORDINATOR_WRITE` | `REGISTER INSTANCE`, `SET INSTANCE ... TO MAIN`, `ADD COORDINATOR`, `YIELD LEADERSHIP`, `FORCE RESET CLUSTER STATE`, … | +| `SET COORDINATOR SETTING` / `SET SETTING` | `COORDINATOR_WRITE` | `SET COORDINATOR SETTING 'sync_failover_only' TO 'true'` | +| `CREATE ROLE` / `DROP ROLE` / `GRANT` / `REVOKE` | `COORDINATOR_WRITE` | `GRANT COORDINATOR_READ TO analyst` | + + +**Breaking change in Memgraph 3.13:** the `COORDINATOR` privilege was removed +and replaced by `COORDINATOR_READ` and `COORDINATOR_WRITE`. It never gated any +operation and is no longer accepted in `GRANT` / `DENY` / `REVOKE` statements. + ## Schema information diff --git a/pages/database-management/authentication-and-authorization/role-based-access-control.mdx b/pages/database-management/authentication-and-authorization/role-based-access-control.mdx index cc2259042..d5ddaf21a 100644 --- a/pages/database-management/authentication-and-authorization/role-based-access-control.mdx +++ b/pages/database-management/authentication-and-authorization/role-based-access-control.mdx @@ -243,7 +243,6 @@ of the following commands: | Privilege to change [storage mode](/fundamentals/storage-memory-usage#storage-modes). | `STORAGE_MODE` | | Privilege to manage [multi-tenant databases](/database-management/multi-tenancy). | `MULTI_DATABASE_EDIT` | | Privilege to use a database within the multi-tenant architecture. | `MULTI_DATABASE_USE` | -| Privilege to configure [high-availability](/clustering/high-availability) coordinators. | `COORDINATOR` | | Privilege to [impersonate other users](/database-management/authentication-and-authorization/impersonate-user). | `IMPERSONATE_USER` | | Privilege to use [parallel execution](/querying/parallel-execution). | `PARALLEL_EXECUTION` | | Privilege to set limits and monitor resource usage per user (via [user profiles](/database-management/authentication-and-authorization/user-profiles)) or per database (via [tenant profiles](/database-management/tenant-profiles)). | `PROFILE_RESTRICTION` | @@ -257,6 +256,22 @@ of the following commands: For a comprehensive reference of which privileges are required for specific queries and operations, see the [Query privileges reference](/database-management/authentication-and-authorization/query-privileges) documentation. + +**Breaking change in Memgraph 3.13:** the `COORDINATOR` privilege was removed — +it never gated any operation. It is no longer accepted in `GRANT` / `DENY` / +`REVOKE` statements and is no longer reported by `SHOW PRIVILEGES`. A stale +`COORDINATOR` grant in an existing deployment is never reported and never +checked, so no migration is needed. + +Access to [high availability](/clustering/high-availability) coordinators is now +controlled by the `COORDINATOR_READ` and `COORDINATOR_WRITE` privileges. These +are **coordinator-only**: they are granted to roles that live on the +coordinators themselves, they are not part of the data-instance privilege set, +and `GRANT ALL PRIVILEGES` on a data instance does not grant them. See +[coordinator +authentication](/clustering/high-availability/coordinator-authentication). + + ### First user privileges When you create the first user in Memgraph, that user automatically becomes a diff --git a/pages/database-management/enabling-memgraph-enterprise.mdx b/pages/database-management/enabling-memgraph-enterprise.mdx index 0c33f655a..5dc2ac744 100644 --- a/pages/database-management/enabling-memgraph-enterprise.mdx +++ b/pages/database-management/enabling-memgraph-enterprise.mdx @@ -245,6 +245,12 @@ ideal solution for those who need a worry-free, highly available system with failover ensures your system remains operational with minimal downtime and manual intervention. +The cluster's control plane can also be secured: [coordinator +authentication](/clustering/high-availability/coordinator-authentication) lets +coordinators authenticate OIDC, SAML and Kerberos connections against your +identity provider and enforce the `COORDINATOR_READ` and `COORDINATOR_WRITE` +privileges on Raft-replicated roles. + ### Multi-tenancy [Multi-tenant support](/database-management/multi-tenancy) enables you to manage diff --git a/pages/release-notes.mdx b/pages/release-notes.mdx index e01e0d244..41b538b80 100644 --- a/pages/release-notes.mdx +++ b/pages/release-notes.mdx @@ -58,6 +58,19 @@ guide. you need the previous Python behavior, or update consumers for the new structured / ISO-8601 JSON forms. [#4443](https://github.com/memgraph/memgraph/pull/4443) +- The `COORDINATOR` privilege was removed — it never gated any operation. It is + no longer accepted in `GRANT` / `DENY` / `REVOKE` statements and is no longer + reported by `SHOW PRIVILEGES`. A stale grant in an existing deployment is + never reported and never checked, so no migration is required. Coordinator + access is now controlled by the new `COORDINATOR_READ` and `COORDINATOR_WRITE` + privileges. + [#4399](https://github.com/memgraph/memgraph/pull/4399) +- Connecting to a coordinator with a username and password is no longer always + accepted. Once `--auth-module-mappings` is set, the enterprise license is + valid, **and** a role holding `COORDINATOR_WRITE` exists, basic authentication + is denied in favor of SSO. Until all three hold, the previous passthrough + behavior is unchanged. + [#4399](https://github.com/memgraph/memgraph/pull/4399) {

🐞 Bug fixes

} @@ -128,6 +141,15 @@ guide. statements). Under index-heavy workloads this removes GC-correlated latency spikes on index and constraint creation. [#4468](https://github.com/memgraph/memgraph/pull/4468) +- Cluster management queries forwarded from a follower coordinator to the leader + now have [explicit RPC + timeouts](/clustering/high-availability/how-high-availability-works#rpc-timeouts), + so a Bolt session can no longer block indefinitely against a leader that is + reachable but stuck. The same applies to MAIN-to-REPLICA system transaction + messages (auth, multi-tenancy, parameters), which now time out after 10s and + defer to system recovery. The unused `EnableWritingOnMainRpc` and its + Prometheus counters were removed. + [#4399](https://github.com/memgraph/memgraph/pull/4399) {

✨ New features

} @@ -160,6 +182,18 @@ guide. - `CREATE RANGE INDEX FOR ... ON ...` now works for nodes and relationships and creates Memgraph’s usual property index. [#4486](https://github.com/memgraph/memgraph/pull/4486) +- [SSO authentication on high availability + coordinators](/clustering/high-availability/coordinator-authentication) + (Enterprise). Coordinators authenticate OIDC, SAML and Kerberos connections + against a Raft-replicated set of roles and enforce two privileges, + `COORDINATOR_READ` and `COORDINATOR_WRITE`. Manage them with `CREATE ROLE`, + `DROP ROLE`, `SHOW ROLES`, `GRANT` / `REVOKE COORDINATOR_READ | + COORDINATOR_WRITE | ALL PRIVILEGES`, and `SHOW PRIVILEGES FOR ROLE` on any + coordinator — follower queries are forwarded to the leader. Basic + authentication stays open until a `COORDINATOR_WRITE` role exists, so no + coordinator restart is needed to roll SSO out, and it reopens if the license + becomes invalid so a coordinator can never lock every session out. + [#4399](https://github.com/memgraph/memgraph/pull/4399) ### Lab v3.13.0 - September 9th, 2026 From 9761fb2a92c955d7862e360aa865e3378ca0af0b Mon Sep 17 00:00:00 2001 From: as51340 Date: Tue, 4 Aug 2026 13:09:29 +0200 Subject: [PATCH 2/5] feat: Remove --init-file comment --- .../coordinator-authentication.mdx | 8 -------- pages/release-notes.mdx | 14 +++++++++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/pages/clustering/high-availability/coordinator-authentication.mdx b/pages/clustering/high-availability/coordinator-authentication.mdx index 9b0907c8f..5bbe2cd65 100644 --- a/pages/clustering/high-availability/coordinator-authentication.mdx +++ b/pages/clustering/high-availability/coordinator-authentication.mdx @@ -506,14 +506,6 @@ SSO logins now find their roles and succeed. - -In containerized deployments you can collapse this into a single start by -creating the roles with -[`--init-file`](/database-management/authentication-and-authorization/auth-system-integrations#docker-deployment-note), -which runs a Cypher script before the database begins serving connections. That -avoids the stop-and-restart cycle entirely. - - Do the coordinator side and the data-instance side with the **same role names**, or [Bolt+routing](#boltrouting-with-sso) connections will fail even though diff --git a/pages/release-notes.mdx b/pages/release-notes.mdx index 41b538b80..3d888a450 100644 --- a/pages/release-notes.mdx +++ b/pages/release-notes.mdx @@ -59,11 +59,15 @@ guide. structured / ISO-8601 JSON forms. [#4443](https://github.com/memgraph/memgraph/pull/4443) - The `COORDINATOR` privilege was removed — it never gated any operation. It is - no longer accepted in `GRANT` / `DENY` / `REVOKE` statements and is no longer - reported by `SHOW PRIVILEGES`. A stale grant in an existing deployment is - never reported and never checked, so no migration is required. Coordinator - access is now controlled by the new `COORDINATOR_READ` and `COORDINATOR_WRITE` - privileges. + no longer accepted in `GRANT` / `DENY` / `REVOKE` statements, which now fail + with a syntax error, and it is no longer reported by `SHOW PRIVILEGES` or + included in `GRANT ALL PRIVILEGES`. Remove any `GRANT COORDINATOR` / + `DENY COORDINATOR` / `REVOKE COORDINATOR` statements from provisioning scripts + and update tooling that compares against the full privilege list. No data + migration is required: a stale grant in an existing deployment is never + reported and never checked. The new `COORDINATOR_READ` and `COORDINATOR_WRITE` + privileges are not a replacement — they are coordinator-only and are rejected + on data instances. [#4399](https://github.com/memgraph/memgraph/pull/4399) - Connecting to a coordinator with a username and password is no longer always accepted. Once `--auth-module-mappings` is set, the enterprise license is From 0d96d9ac8752fcf0a990186f4671a4d07d45dfdd Mon Sep 17 00:00:00 2001 From: as51340 Date: Tue, 4 Aug 2026 13:18:20 +0200 Subject: [PATCH 3/5] fix: Notes if SSO on data instances is already set-up --- .../high-availability/coordinator-authentication.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pages/clustering/high-availability/coordinator-authentication.mdx b/pages/clustering/high-availability/coordinator-authentication.mdx index 5bbe2cd65..836d8a4c7 100644 --- a/pages/clustering/high-availability/coordinator-authentication.mdx +++ b/pages/clustering/high-availability/coordinator-authentication.mdx @@ -477,6 +477,13 @@ SHOW PRIVILEGES FOR ROLE dba; ### On data instances — restart required + +This only concerns data instances where SSO is **not** set up yet. If your data +instances already authenticate through SSO, nothing changes for them — enabling +SSO on the coordinators does not require any modification on the data-instance +side, beyond using the [same role names](#boltrouting-with-sso) on both sides. + + Data instances have no equivalent escape hatch. Their SSO path validates the IdP's roles against the auth store, and a role that does not exist means the login fails. If you enable the module before the roles exist, SSO users cannot From cab005af4927171c8f3c9d9ae291cb1a8a3b584a Mon Sep 17 00:00:00 2001 From: as51340 Date: Tue, 4 Aug 2026 13:20:47 +0200 Subject: [PATCH 4/5] fix: State definitively that --init-file is unsupported in HA mode --- .../auth-system-integrations.mdx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx b/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx index a91170d5c..252430ec0 100644 --- a/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx +++ b/pages/database-management/authentication-and-authorization/auth-system-integrations.mdx @@ -154,9 +154,14 @@ This approach ensures that all roles are created before the external authentication module is activated, allowing users to log in seamlessly across all supported authentication methods. -If you cannot use `--init-file`, the equivalent manual procedure is to start the -data instance **without** `--auth-module-mappings`, log in, create the roles and -grant their privileges, then restart with the flag set. +This workflow only applies to standalone Memgraph instances. On [data instances +running in HA +mode](/clustering/high-availability/how-high-availability-works#data-instance-implementation) +(i.e. when `--management-port` is set), `--init-file` is **not supported** and +the instance will fail to start if the flag is provided. There you must use the +manual procedure instead: start the data instance **without** +`--auth-module-mappings`, log in, create the roles and grant their privileges, +then restart with the flag set. From Memgraph 3.13, [high availability From 2a89359299a6bc0cf4913983e41032ff7449ab6f Mon Sep 17 00:00:00 2001 From: Andi Skrgat Date: Wed, 12 Aug 2026 12:17:45 +0200 Subject: [PATCH 5/5] docs: SHOW VERSION query (#1715) --- .../high-availability/coordinator-authentication.mdx | 1 + .../high-availability/how-high-availability-works.mdx | 6 +++--- .../authentication-and-authorization/query-privileges.mdx | 3 ++- pages/database-management/server-stats.mdx | 7 +++++++ pages/release-notes.mdx | 6 ++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pages/clustering/high-availability/coordinator-authentication.mdx b/pages/clustering/high-availability/coordinator-authentication.mdx index 836d8a4c7..6ec9b1223 100644 --- a/pages/clustering/high-availability/coordinator-authentication.mdx +++ b/pages/clustering/high-availability/coordinator-authentication.mdx @@ -93,6 +93,7 @@ satisfies a `COORDINATOR_READ` requirement, but not the other way round. | `SHOW ROLES` | `COORDINATOR_READ` | | `SHOW PRIVILEGES FOR ROLE ` | `COORDINATOR_READ` | | `SHOW CONFIG`, `SHOW SETTING`, system info queries | `COORDINATOR_READ` | +| [`SHOW VERSION`](/database-management/server-stats#instance-version) | `COORDINATOR_READ` | | `SHOW CURRENT USER`, `SHOW CURRENT ROLE` | **None** (self-service, see [below](#self-service-identity-queries)) | | [`REGISTER INSTANCE`](/clustering/high-availability/ha-commands-reference#register-instance) / [`UNREGISTER INSTANCE`](/clustering/high-availability/ha-commands-reference#unregister-instance) | `COORDINATOR_WRITE` | | [`SET INSTANCE ... TO MAIN`](/clustering/high-availability/ha-commands-reference#set-instance--to-main) / [`DEMOTE INSTANCE`](/clustering/high-availability/ha-commands-reference#demote-instance) | `COORDINATOR_WRITE` | diff --git a/pages/clustering/high-availability/how-high-availability-works.mdx b/pages/clustering/high-availability/how-high-availability-works.mdx index 782f53cd4..1ee9f9a4e 100644 --- a/pages/clustering/high-availability/how-high-availability-works.mdx +++ b/pages/clustering/high-availability/how-high-availability-works.mdx @@ -116,9 +116,9 @@ The COORDINATOR instance is a **very restricted instance**, and it will not respond to any queries that are not related to management of the cluster. That means, you cannot run any data queries on the coordinator directly (we will talk more about routing data queries in the next sections). However, -system information queries such as `SHOW CONFIG`, `SHOW LICENSE INFO`, -`SHOW BUILD INFO` and `SHOW STORAGE INFO` are supported on coordinators, as -well as `SET DATABASE SETTING`, `RELOAD BOLT_SERVER TLS` and +system information queries such as `SHOW CONFIG`, `SHOW VERSION`, +`SHOW LICENSE INFO`, `SHOW BUILD INFO` and `SHOW STORAGE INFO` are supported on +coordinators, as well as `SET DATABASE SETTING`, `RELOAD BOLT_SERVER TLS` and `RELOAD INTRA_CLUSTER TLS`. diff --git a/pages/database-management/authentication-and-authorization/query-privileges.mdx b/pages/database-management/authentication-and-authorization/query-privileges.mdx index 034e9885b..6ef42f8c9 100644 --- a/pages/database-management/authentication-and-authorization/query-privileges.mdx +++ b/pages/database-management/authentication-and-authorization/query-privileges.mdx @@ -143,7 +143,7 @@ Memgraph's privilege system controls access to various database operations throu | `SHOW SNAPSHOTS` | `DURABILITY` | `SHOW SNAPSHOTS` | | `SHOW NEXT SNAPSHOT` | `DURABILITY` | `SHOW NEXT SNAPSHOT` | | `SET SETTING` | `CONFIG` | `SET SETTING ...` | -| `SHOW VERSION` | `STATS` | `SHOW VERSION` | +| `SHOW VERSION` | `STATS` | `SHOW VERSION` — on coordinators it requires `COORDINATOR_READ` instead, see [Coordinator operations](#coordinator-operations). | | `SHOW TRANSACTIONS` | `TRANSACTION_MANAGEMENT` | `SHOW TRANSACTIONS` | | `TERMINATE TRANSACTIONS` | `TRANSACTION_MANAGEMENT` | `TERMINATE TRANSACTIONS 'transaction_id'` | | `RELOAD BOLT_SERVER TLS` | `RELOAD_TLS` | `RELOAD BOLT_SERVER TLS` | @@ -210,6 +210,7 @@ coordinator with basic auth carries both implicitly. | `SHOW REPLICATION LAG` | `COORDINATOR_READ` | `SHOW REPLICATION LAG` | | `SHOW ROLES` / `SHOW PRIVILEGES FOR ROLE` | `COORDINATOR_READ` | `SHOW PRIVILEGES FOR ROLE dba` | | `SHOW CONFIG`, `SHOW SETTING`, system info queries | `COORDINATOR_READ` | `SHOW CONFIG` | +| `SHOW VERSION` | `COORDINATOR_READ` | `SHOW VERSION` | | `SHOW CURRENT USER` / `SHOW CURRENT ROLE` | **None** | Self-service identity queries. | | Cluster management operations | `COORDINATOR_WRITE` | `REGISTER INSTANCE`, `SET INSTANCE ... TO MAIN`, `ADD COORDINATOR`, `YIELD LEADERSHIP`, `FORCE RESET CLUSTER STATE`, … | | `SET COORDINATOR SETTING` / `SET SETTING` | `COORDINATOR_WRITE` | `SET COORDINATOR SETTING 'sync_failover_only' TO 'true'` | diff --git a/pages/database-management/server-stats.mdx b/pages/database-management/server-stats.mdx index 86bbec23e..4ecb31308 100644 --- a/pages/database-management/server-stats.mdx +++ b/pages/database-management/server-stats.mdx @@ -18,6 +18,13 @@ To get the version of the instance being queried, run the following query: SHOW VERSION; ``` +The query can be run on data instances and on +[coordinators](/clustering/high-availability), so you can check the version of +every instance in a high-availability cluster without connecting through the +MAIN. On data instances it requires the `STATS` privilege; on coordinators it is +a read-only query that requires +[`COORDINATOR_READ`](/clustering/high-availability/coordinator-authentication#which-privilege-each-query-requires). + ## Storage information `SHOW STORAGE INFO` comes in two flavors: diff --git a/pages/release-notes.mdx b/pages/release-notes.mdx index 3d888a450..106cfafc7 100644 --- a/pages/release-notes.mdx +++ b/pages/release-notes.mdx @@ -198,6 +198,12 @@ guide. coordinator restart is needed to roll SSO out, and it reopens if the license becomes invalid so a coordinator can never lock every session out. [#4399](https://github.com/memgraph/memgraph/pull/4399) +- `SHOW VERSION` can now be run on coordinators, alongside the other read-only + introspection queries such as `SHOW CONFIG` and `SHOW BUILD INFO`. It + previously failed with `Coordinator can run only coordinator queries!`. On + coordinators it is a `COORDINATOR_READ` query, so an SSO role with only + `COORDINATOR_READ` granted can run it. + [#4535](https://github.com/memgraph/memgraph/pull/4535) ### Lab v3.13.0 - September 9th, 2026