Chapter 13: Security
A production graph database must protect the data it holds. AstraeaDB provides layered security: token-based authentication with role-based access control, TLS encryption for data in transit, an experimental homomorphic encryption engine for privacy-sensitive workloads, and comprehensive audit logging. This chapter walks through each layer, from the simplest configuration to the most advanced.
13.1 Authentication (API Keys and RBAC)
AstraeaDB uses token-based authentication combined with Role-Based Access Control (RBAC). Every client connection must present a valid authentication token, and the token determines what operations the client is allowed to perform.
The Three Roles
AstraeaDB defines three built-in roles, each a strict superset of the one below it:
| Role | Permissions | Typical Use |
|---|---|---|
Reader |
Query nodes and edges, run graph algorithms, execute vector searches, read properties | Dashboard applications, reporting services, read-only API endpoints |
Writer |
All Reader permissions plus create, update, and delete nodes and edges | Application backends, ETL pipelines, data ingestion services |
Admin |
All Writer permissions plus user management, configuration changes, audit log access, backup/restore | Operations teams, database administrators |
Connecting with Authentication
Pass your authentication token when creating the client connection. Here is how it looks in each supported language:
from astraeadb import AstraeaClient # Connect with a Writer token with AstraeaClient("127.0.0.1", 7687, auth_token="my-secret-token") as client: # This succeeds with Writer or Admin role client.create_node(["Person"], {"name": "Alice", "age": 30}) # This succeeds with any role (Reader, Writer, or Admin) result = client.query( 'MATCH (p:Person) RETURN p.name' ) print(result)
source("r_client.R") client <- AstraeaClient$new("127.0.0.1", 7687, auth_token = "my-secret-token") client$connect() # Create a node (requires Writer or Admin) client$create_node(c("Person"), list(name = "Alice", age = 30)) # Query (any role) result <- client$query("MATCH (p:Person) RETURN p.name") print(result) client$close()
package main import ( "context" "fmt" "github.com/AstraeaDB/AstraeaDB-Official" ) func main() { client := astraeadb.NewClient( astraeadb.WithAddress("127.0.0.1", 7687), astraeadb.WithAuthToken("my-secret-token"), ) ctx := context.Background() client.Connect(ctx) defer client.Close() // Create a node (requires Writer or Admin) client.CreateNode(ctx, []string{"Person"}, map[string]any{ "name": "Alice", "age": 30, }) // Query (any role) result, _ := client.Query(ctx, "MATCH (p:Person) RETURN p.name") fmt.Println(result) }
import com.astraeadb.unified.UnifiedClient; import java.util.List; import java.util.Map; try (var client = UnifiedClient.builder() .host("127.0.0.1").port(7687) .authToken("my-secret-token") .build()) { client.connect(); // Create a node (requires Writer or Admin) client.createNode( List.of("Person"), Map.of("name", "Alice", "age", 30) ); // Query (any role) var result = client.query("MATCH (p:Person) RETURN p.name"); System.out.println(result); }
Permission Denied Errors
If a client attempts an operation that exceeds its role, AstraeaDB returns a clear error. For example, a Reader token attempting to create a node:
# Python example: Reader trying to write with AstraeaClient("127.0.0.1", 7687, auth_token="reader-only-token") as client: try: client.create_node(["Person"], {"name": "Bob"}) except PermissionError as e: print(e) # PermissionError: role 'Reader' does not have 'write' permission
13.2 TLS and Mutual TLS (mTLS)
By default, AstraeaDB communicates over unencrypted TCP. For production deployments, you should enable TLS (Transport Layer Security) to encrypt all traffic between clients and the server.
Standard TLS
Standard TLS encrypts the connection and verifies the server's identity. The client trusts the server based on its certificate, but the server accepts any client that connects.
Configure TLS in your astraeadb.toml:
# astraeadb.toml - TLS Configuration [tls] cert_path = "/path/to/server.crt" # Server certificate (PEM format) key_path = "/path/to/server.key" # Server private key (PEM format)
With TLS enabled, the server only accepts encrypted connections. Clients must connect using TLS:
from astraeadb import AstraeaClient with AstraeaClient( "db.example.com", 7687, auth_token="my-secret-token", tls=True, ca_cert="/path/to/ca.crt" # CA that signed the server cert ) as client: result = client.ping() print(result)
source("r_client.R") client <- AstraeaClient$new( "db.example.com", 7687, auth_token = "my-secret-token", tls = TRUE, ca_cert = "/path/to/ca.crt" ) client$connect() result <- client$ping() print(result) client$close()
package main import ( "context" "fmt" "github.com/AstraeaDB/AstraeaDB-Official" ) func main() { client := astraeadb.NewClient( astraeadb.WithAddress("db.example.com", 7687), astraeadb.WithAuthToken("my-secret-token"), astraeadb.WithTLS("/path/to/ca.crt"), ) ctx := context.Background() client.Connect(ctx) defer client.Close() result, _ := client.Ping(ctx) fmt.Println(result) }
import com.astraeadb.unified.UnifiedClient; try (var client = UnifiedClient.builder() .host("db.example.com").port(7687) .authToken("my-secret-token") .tls(true) .caCert("/path/to/ca.crt") .build()) { client.connect(); var result = client.ping(); System.out.println(result); }
Mutual TLS (mTLS)
Standard TLS verifies the server to the client. Mutual TLS goes further: both the client and the server present certificates. This provides two-way identity verification and is the gold standard for zero-trust network architectures.
With mTLS, the client certificate's Common Name (CN) is mapped to an RBAC role. This eliminates the need for separate API tokens—the certificate itself is the credential.
Server Configuration
# astraeadb.toml - Mutual TLS Configuration [tls] cert_path = "/path/to/server.crt" # Server certificate key_path = "/path/to/server.key" # Server private key ca_cert_path = "/path/to/ca.crt" # CA cert to verify client certs [tls.client_role_mapping] # Map certificate CN to RBAC role "analytics-service" = "Reader" "ingestion-pipeline" = "Writer" "ops-team" = "Admin"
How mTLS Authentication Works
- The client connects and presents its certificate (signed by the trusted CA).
- The server verifies the client certificate against the CA certificate at
ca_cert_path. - The server extracts the Common Name (CN) from the client certificate.
- The CN is matched against the
client_role_mappingto determine the RBAC role. - If the CN is not in the mapping, the connection is rejected.
13.3 Homomorphic Encryption
AstraeaDB includes an experimental homomorphic encryption engine for workloads where even the database server should not see the unencrypted data. This is a cutting-edge research feature designed for privacy-sensitive domains such as banking and healthcare.
The Concept
In a traditional database, the server must decrypt data to query it. This means anyone with access to the server (administrators, attackers who breach the perimeter) can read the data. Homomorphic encryption allows computations on encrypted data without ever decrypting it. The server stores encrypted values, performs matching on encrypted values, and returns encrypted results that only the client can decrypt.
How It Works in AstraeaDB
AstraeaDB supports deterministic encrypted label matching. The workflow is as follows:
Because the encryption is deterministic (the same plaintext always produces the same ciphertext), the server can perform equality matching without ever knowing the underlying values.
Use Cases
| Domain | Scenario | Benefit |
|---|---|---|
| Banking | Query customer relationship graphs without exposing PII (names, account numbers) | Database administrators cannot see customer data even with full server access |
| Healthcare | Analyze patient interaction graphs while maintaining HIPAA compliance | Research teams can run graph queries without being exposed to protected health information |
| Government | Cross-agency intelligence sharing on classified graphs | Each agency can query shared infrastructure without revealing sensitive entity names |
Enabling Homomorphic Encryption
# astraeadb.toml - Homomorphic Encryption [encryption] homomorphic_enabled = true # The encryption keys are managed client-side. # The server never holds the decryption key.
13.4 Audit Logging
Every operation in AstraeaDB can be recorded in an audit log. This provides a tamper-evident record of who did what, when, and from where—essential for compliance, incident investigation, and security monitoring.
What Gets Logged
Each audit log entry contains:
- Timestamp — precise time of the operation (millisecond resolution)
- User / Token ID — which authenticated identity performed the action
- Operation Type —
CREATE_NODE,DELETE_EDGE,QUERY,ADMIN_CONFIG_CHANGE, etc. - Target — the node ID, edge ID, or query string involved
- Source IP — the client's network address
- Result — success or failure (with error code if applicable)
Storage and Retention
Audit logs are stored in a circular buffer that maintains recent operation history in memory for fast access. Older entries are flushed to disk. The buffer size is configurable:
# astraeadb.toml - Audit Logging [audit] enabled = true buffer_size = 100000 # Number of entries in the circular buffer flush_to_disk = true log_path = "/var/log/astraeadb/audit.log"
Accessing the Audit Log
Admin-role users can query the audit log through the client API:
# Python: retrieve recent audit entries with AstraeaClient("127.0.0.1", 7687, auth_token="admin-token") as client: entries = client.audit_log(limit=50) for entry in entries: print(f"[{entry['timestamp']}] " f"{entry['user']} " f"{entry['operation']} " f"{entry['result']}")
Example output:
[2026-02-21T14:30:01.123Z] writer-svc CREATE_NODE success
[2026-02-21T14:30:01.456Z] reader-app QUERY success
[2026-02-21T14:30:02.789Z] reader-app CREATE_NODE DENIED (insufficient permissions)
[2026-02-21T14:30:03.012Z] admin-ops CONFIG_CHANGE success
Security Summary
AstraeaDB's security model is designed in layers. Each layer addresses a different threat:
| Layer | Protects Against | Mechanism |
|---|---|---|
| Authentication (RBAC) | Unauthorized access | Token-based identity with role-based permissions |
| TLS / mTLS | Eavesdropping, man-in-the-middle attacks | Encrypted transport with certificate-based identity |
| Homomorphic Encryption | Insider threats, server compromise | Encrypted-at-rest with server-side blind matching |
| Audit Logging | Undetected misuse, compliance gaps | Complete operation history with identity attribution |