Documentation

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:

OperatorSymbolMeaning
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

ExpressionWho can see it
publicAnyone with the "public" authorization
engineeringAnyone with the "engineering" authorization
engineering&managementUsers with both "engineering" AND "management"
engineering|salesUsers with either "engineering" OR "sales"
(engineering|sales)&confidentialUsers 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.

API key with authorizationsjson
{
  "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 both
  • sales — 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

You configure authorizations when creating an API key in the dashboard. Different keys for the same cluster can have different authorization sets, enabling fine-grained access control for different services or users.

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:

Public vertexbash
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:

Department-scoped vertexbash
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:

Multi-tenant verticesbash
# 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:

  1. A client request arrives at the Veculo API with an API key
  2. Veculo resolves the API key's authorizations
  3. Veculo opens an Accumulo scanner with those authorizations
  4. The tablet server reads each cell from the sorted key-value store
  5. For each cell, the tablet server parses the visibility expression and evaluates it against the provided authorizations
  6. Cells that do not match are silently dropped — they are never sent over the network
  7. 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

Because visibility filtering happens at the storage layer, you do not need to implement access control in your application code. The data simply does not appear if the caller lacks the required authorizations.

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.