Chapter 15 · Security: Authentication, RBAC, Privileges, TLS, Secrets, and Least Privilege
Database, Graph, Label/Type, Procedure, and Other Privileges: Designing Least-Privilege Roles
Turn AtlasMart service requirements into explicit allows and denies across database, graph, property, mutation and procedure surfaces without hiding Community RBAC limitations.
Learning outcomes
AtlasMart has three service personas: a catalog reader, an order
writer and an operations administrator. Giving all three
admin is easy, but it destroys the security
boundary. This lesson designs the privilege set from required
actions and negative tests rather than from built-in role names
alone.
Map application operations to database ACCESS, graph MATCH/WRITE/MERGE and schema/name-management privileges.
Distinguish node-label, relationship-type and property read/write privileges from broad graph access.
Control procedure/function execution and explain why boosted execution is a separate risk.
Use positive and denied-query tests as executable least-privilege requirements.
Document the Community authorization gap and choose application/deployment controls without pretending they equal database RBAC.
The continuity lab remains Neo4j Community
2026.07.1, database neo4j, explicit
CYPHER 25 where language behavior matters,
container atlasmart-neo4j, loopback Bolt
bolt://127.0.0.1:7687, synthetic credential
neo4j/atlasmart-course-2026,
official Python driver neo4j 6.3.0, and no
mandatory plugin. Neo4j 5.26.30 is the LTS
comparison line. For TLS changes, this chapter deliberately
uses a second disposable container
atlasmart-neo4j-secure so earlier labs are not
disrupted.
Current Community Edition supports native users but has no roles; every Community user has implied administrator privileges. Fine-grained RBAC, built-in/custom roles, graph/database/procedure privileges, external auth-provider integration, security/query logs and related enterprise authorization controls are Enterprise/Aura-tier features. Mandatory Community exercises therefore prove authentication, parameterization, TLS, credential rotation and application-layer authorization, while RBAC denial examples are explicitly marked licensed/deterministic rather than presented as Community output.
All credentials, certificates and attacks in this chapter are synthetic and disposable. Never paste production passwords/private keys into source control, do not disable certificate verification to make a production connection work, and do not broaden procedure/plugin privileges merely to get a demo running.
Reproducible AtlasMart setup
$env:NEO4J_URI='bolt://127.0.0.1:7687'$env:NEO4J_USER='neo4j'$env:NEO4J_PASSWORD='atlasmart-course-2026'$env:NEO4J_DATABASE='neo4j'py -3 -m venv .venv.\.venv\Scripts\Activate.ps1python -m pip install --upgrade pippython -m pip install neo4j==6.3.0
CYPHER 25CREATE CONSTRAINT customer_id IF NOT EXISTSFOR (c:Customer) REQUIRE c.customerId IS UNIQUE;CREATE CONSTRAINT product_id IF NOT EXISTSFOR (p:Product) REQUIRE p.productId IS UNIQUE;CREATE CONSTRAINT order_id IF NOT EXISTSFOR (o:Order) REQUIRE o.orderId IS UNIQUE;MERGE (c:Customer {customerId:'C-1001'})SET c.name='Mina Rahimi', c.tier='GOLD', c.tenantId='TENANT-A'MERGE (p:Product {productId:'P-1001'})SET p.name='Trail Camera', p.category='Cameras', p.price=129.90MERGE (o:Order {orderId:'O-5001'})SET o.status='PAID', o.tenantId='TENANT-A', o.orderedAt=datetime('2026-09-08T16:30:00Z')MERGE (c)-[:PLACED]->(o)MERGE (o)-[r:CONTAINS]->(p)SET r.quantity=1, r.unitPrice=129.90;
These are course-only credentials and synthetic records. The
fixture deliberately includes tenantId because
authorization mistakes often appear when a graph traversal
crosses a tenant boundary even though authentication succeeded.
1. Start from operations, not role names
| AtlasMart operation | Required graph behavior | Should be denied |
|---|---|---|
| catalog search | read Product/Category and IN_CATEGORY | Order/Customer PII writes |
| order read | read Order plus PLACED/CONTAINS and selected Customer fields | schema/user administration |
| order status update | find an Order and set status | delete arbitrary Customer/Product |
| support diagnostics | read bounded operational metadata | execute boosted custom procedures by default |
| DB administration | users, roles, schema, backup/server operations | application request path |
Least privilege means the service can complete its contract and nothing more. The test suite must contain denied operations; otherwise “least” is not being verified.
2. Privilege layers in Enterprise/Aura-capable tiers
| Layer | Representative privilege | Mechanism |
|---|---|---|
| Database admission | ACCESS ON DATABASE neo4j |
may connect/use database |
| Graph traversal + properties | MATCH {…} ON GRAPH |
combines TRAVERSE and READ |
| Fine-grained writes |
CREATE, DELETE,
SET PROPERTY, MERGE
|
limit mutation scope |
| Schema/name creation | CREATE NEW LABEL/TYPE/PROPERTY NAME, INDEX/CONSTRAINT privileges | separate from graph data writes |
| Procedures/functions | EXECUTE PROCEDURE/FUNCTION | whether extension may run |
| Boosted execution | EXECUTE BOOSTED PROCEDURE/FUNCTION | procedure executes with privileges beyond caller; high-risk |
3. Reader role with an explicit property contract
CREATE ROLE atlasmart_reader IF NOT EXISTS;CREATE USER atlasmart_reader_user IF NOT EXISTSSET PASSWORD $readerPassword CHANGE NOT REQUIRED;GRANT ROLE atlasmart_reader TO atlasmart_reader_user;GRANT ACCESS ON DATABASE neo4j TO atlasmart_reader;GRANT MATCH {customerId, name, tier, tenantId} ON GRAPH neo4j NODES Customer TO atlasmart_reader;GRANT MATCH {orderId, status, orderedAt, tenantId} ON GRAPH neo4j NODES Order TO atlasmart_reader;GRANT MATCH {productId, name, category, price} ON GRAPH neo4j NODES Product TO atlasmart_reader;GRANT MATCH {*} ON GRAPH neo4j RELATIONSHIPS PLACED, CONTAINS TO atlasmart_reader;SHOW ROLE atlasmart_reader PRIVILEGES AS COMMANDS;
Property allowlists are safer than {*} when new
properties could contain secrets/PII. The tradeoff is
schema-evolution work: a newly required property must be
deliberately granted.
4. Order writer without broad WRITE
CREATE ROLE atlasmart_order_writer IF NOT EXISTS;GRANT ACCESS ON DATABASE neo4j TO atlasmart_order_writer;GRANT MATCH {orderId, status, tenantId} ON GRAPH neo4j NODES Order TO atlasmart_order_writer;GRANT SET PROPERTY {status} ON GRAPH neo4j NODES Order TO atlasmart_order_writer;// Deliberately do NOT grant DELETE, user management,// index/constraint management, or broad WRITE.SHOW ROLE atlasmart_order_writer PRIVILEGES AS COMMANDS;
CYPHER 25MATCH (o:Order {orderId:$orderId, tenantId:$tenantId})SET o.status=$statusRETURN o.orderId, o.status;
CYPHER 25MATCH (c:Customer {customerId:$customerId})DETACH DELETE c;
5. Procedure execution is an authorization surface
CREATE ROLE atlasmart_visualizer IF NOT EXISTS;GRANT EXECUTE PROCEDURE db.schema.visualization ON DBMS TO atlasmart_visualizer;// Boosting is intentionally not granted.SHOW ROLE atlasmart_visualizer PRIVILEGES AS COMMANDS;
Execution permission and the caller’s graph privileges are separate. A normal procedure call runs under the user’s effective privileges. Boosted execution can exceed them, so it should be rare, explicit, reviewed and tested as a privileged code path.
6. Community deterministic fallback
| Requirement | Community local learning path | What it cannot prove |
|---|---|---|
| catalog read only | application only exposes parameterized read repository methods | DB user still has admin capability |
| tenant boundary | repository requires tenantId and negative cross-tenant tests | compromised arbitrary Cypher client could bypass app layer |
| no schema/admin from app | service process exposes no admin endpoint and uses isolated secret | DB credential itself remains admin |
| procedure governance | do not install unnecessary plugins; review allowlist/unrestricted config | cannot demonstrate Enterprise EXECUTE DENY/GRANT |
| hard isolation | separate Community DBMS/container/network credential for different trust zone | more operational overhead; not fine-grained in one DBMS |
An application repository layer is necessary even with RBAC, but it is not a replacement for database authorization when arbitrary DB credentials are compromised. If DB-enforced least privilege is a requirement, tier/deployment choice is part of the security architecture.
7. Privilege regression tests
CASES = [ ("read-own-order", "expected_allow"), ("read-cross-tenant-order", "expected_deny"), ("set-order-status", "expected_allow"), ("delete-customer", "expected_deny"), ("create-index", "expected_deny"), ("show-users", "expected_deny"),]# In Enterprise/Aura-capable RBAC tests, authenticate as the service user# and assert the DBMS actually denies the forbidden statements.# In Community, mark DB-level deny cases UNSUPPORTED rather than falsely PASS.
Production judgment
| Review area | Decision evidence |
|---|---|
| Identity/authentication | native or external identity source, MFA/SSO upstream where available, password/token lifecycle, lockout and break-glass process |
| Authorization | least-privilege database/graph/procedure grants; explicit DENY review; Community control gap documented |
| Transport | encrypted remote Bolt/HTTPS, trusted CA and hostname validation; self-signed only for isolated testing |
| Secrets | out of source/logs/images; rotated without code changes; incident revocation path tested |
| Application layer | parameterized Cypher, tenant/subject authorization before graph expansion, bounded result/data-export paths |
| Extensions/admin | procedure allowlist/unrestricted/boosted review, plugin provenance, backup/admin filesystem and host access |
| Evidence | auth/TLS denial tests, security/query logs where licensed, driver/server correlation and configuration review |
| Recovery | credential compromise playbook, backup encryption/access, break-glass scope, rollback/reconciliation and post-incident validation |
Check your understanding
- What does MATCH privilege combine?
- Why avoid broad WRITE for an order-status service?
- Is EXECUTE BOOSTED just a faster procedure permission?
- Can Community prove a database-level denied delete?
- Why include negative authorization tests?
Review the answers
1. TRAVERSE and READ for the targeted entities/properties.
2. WRITE grants all graph write operations; the service usually needs only narrow read plus SET PROPERTY on status.
3. No. It changes the privilege context and can exceed caller privileges, materially increasing blast radius.
4. Not through RBAC, because Community has no roles and users are implied admins.
5. A least-privilege design is incomplete unless forbidden operations are actually verified as denied.
Summary and next step
Least privilege is an executable contract across database admission, graph elements, properties, writes, schema and extensions. Lesson 3 protects those authenticated/authorized operations in transit and shows why encryption without certificate verification is not enough.
Authoritative references
- Current Neo4j versions — Current server and 5.26 LTS release snapshot.
- Security checklist — Official baseline for deployment, transport, extensions, backup and filesystem security.
- Manage users — Native users, password handling, Community/Enterprise user-model distinctions.
- Role-based access control — Enterprise RBAC model and GRANT/DENY/REVOKE semantics.
- Read privileges — TRAVERSE, READ and MATCH graph privilege semantics.
- Write privileges — CREATE, DELETE, SET, MERGE and WRITE privilege semantics.
- SSL framework — Bolt/HTTPS TLS policies, certificate files, TLS levels and URI schemes.
- Procedure/function privileges — Execute and boosted-execution privilege boundaries.
- Python driver advanced connections — TLS/trust and rotating authentication token support in the maintained Python driver.
- Built-in roles — Enterprise/Aura built-in role capabilities.
- DBMS privileges — System-wide administrative privilege model.
- Access-control limitations — Subgraph/label visibility nuances relevant to fine-grained authorization.