Security & ABAC
Cell-level security with visibility expressions and attribute-based access control, enforced at the storage layer.
Cell-level security overview
Veculo inherits its security model from Apache Accumulo, which provides cell-level security — every individual piece of data (every vertex, every edge, every property) carries its own visibility label. When a query scans data, the storage layer filters out any cells the caller is not authorized to see. This happens below the query engine, making it impossible for application code to bypass.
This is fundamentally different from row-level security (RLS) in relational databases. With cell-level security:
- Two users querying the same vertex can see different properties based on their authorizations
- A graph traversal automatically skips edges the caller cannot see — no application logic required
- Vector search only returns vertices the caller is authorized to access
- Security is enforced at the tablet server level, not in application middleware
Visibility expressions
A visibility expression is a boolean expression attached to a vertex or edge that defines who can see it. Expressions use three operators:
| Operator | Symbol | Meaning |
|---|---|---|
| AND | & | Caller must have both authorizations |
| OR | | | Caller must have at least one authorization |
| Grouping | ( ) | Control evaluation order |
Authorization labels are arbitrary strings you define. They can represent any dimension of access: departments, projects, roles, customer IDs — whatever your application needs.
Expression examples
| Expression | Who can see it |
|---|---|
public | Anyone with the "public" authorization |
engineering | Anyone with the "engineering" authorization |
engineering&management | Users with both "engineering" AND "management" |
engineering|sales | Users with either "engineering" OR "sales" |
(engineering|sales)&confidential | Users with "confidential" who are in engineering or sales |
tenant:acme&(admin|analyst) | Acme tenant users who are admin or analyst |
How authorizations work
Each API key has a set of authorizations — the labels that key is permitted to resolve. When a request arrives, Veculo passes the key's authorizations to the Accumulo scanner. The scanner evaluates every cell's visibility expression against those authorizations and only returns cells that match.
{
"key_id": "vk_live_abc123def456",
"authorizations": ["public", "engineering", "confidential"],
"cluster_id": "cls_abc123",
"created_at": "2026-03-21T10:00:00Z"
}With the authorizations above, this key can see:
public— yes, the key has "public"engineering&confidential— yes, the key has bothsales— no, the key lacks "sales"engineering|sales— yes, the key has "engineering"sales&confidential— no, the key lacks "sales"
Authorizations are set per API key
Practical examples
Public data
For data that should be visible to all authenticated users, use a single label like public and include it in every API key's authorizations:
curl -X POST "https://api.veculo.com/v1/cls_abc123/vertices" \
-H "Authorization: Bearer vk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"id": "doc:getting-started",
"label": "document",
"properties": {
"title": "Getting Started Guide",
"category": "onboarding"
},
"visibility": "public"
}'Department-scoped data
Restrict data to specific departments. Only API keys with the matching authorization can read it:
curl -X POST "https://api.veculo.com/v1/cls_abc123/vertices" \
-H "Authorization: Bearer vk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"id": "report:q4-2025-financials",
"label": "report",
"properties": {
"title": "Q4 2025 Financial Report",
"quarter": "Q4-2025"
},
"visibility": "finance&confidential"
}'Only API keys with both finance and confidential authorizations will see this vertex.
Multi-tenant isolation
For SaaS applications where multiple customers share a cluster, use tenant-prefixed labels:
# Data for Acme Corp
curl -X POST "https://api.veculo.com/v1/cls_abc123/vertices" \
-H "Authorization: Bearer vk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"id": "customer:acme-001",
"label": "customer",
"properties": { "name": "Acme Corp", "plan": "enterprise" },
"visibility": "tenant:acme"
}'
# Data for Globex Inc
curl -X POST "https://api.veculo.com/v1/cls_abc123/vertices" \
-H "Authorization: Bearer vk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"id": "customer:globex-001",
"label": "customer",
"properties": { "name": "Globex Inc", "plan": "growth" },
"visibility": "tenant:globex"
}'An API key with authorization tenant:acme will only see Acme data. A key with tenant:globex will only see Globex data. Even if the data is in the same table, cross-tenant access is impossible at the storage layer.
How Accumulo enforces visibility
Visibility enforcement happens inside the Accumulo tablet server during the scan process — not in Veculo's API layer. Here is the flow:
- A client request arrives at the Veculo API with an API key
- Veculo resolves the API key's authorizations
- Veculo opens an Accumulo scanner with those authorizations
- The tablet server reads each cell from the sorted key-value store
- For each cell, the tablet server parses the visibility expression and evaluates it against the provided authorizations
- Cells that do not match are silently dropped — they are never sent over the network
- The surviving cells are returned to Veculo, which assembles the response
This design means visibility is enforced even if there is a bug in Veculo's API layer. The tablet server is the security boundary.
Zero-trust data access
Defense in depth
Veculo provides multiple layers of security:
- Per-tenant clusters — Each customer gets their own isolated Accumulo instance, ZooKeeper ensemble, and GCS storage prefix. There is no shared state between tenants.
- Cell-level visibility — Even within a single tenant's cluster, different users or services can have different views of the same data using visibility expressions.
- API key scoping — Keys can be scoped with specific authorizations, making it safe to issue keys to different services or third parties.
- TLS everywhere — All data in transit is encrypted. API endpoints are HTTPS-only.
- Encryption at rest — Data is encrypted in GCS using Google-managed or customer-managed encryption keys (CMEK).
- Audit logging — All API requests are logged with the API key used, authorizations resolved, and resources accessed.