https://github.com/somoore/powerpipe-turbopuffer-security-benchmark
Powerpipe mod: 16 security controls (tenant isolation, data residency, CMEK, schema hygiene, ops) and branded dashboards for turbopuffer namespaces. Runs over the somoore/turbopuffer Steampipe plugin.
https://github.com/somoore/powerpipe-turbopuffer-security-benchmark
compliance powerpipe powerpipe-mod security sql steampipe turbopuffer vector-search
Last synced: 1 day ago
JSON representation
Powerpipe mod: 16 security controls (tenant isolation, data residency, CMEK, schema hygiene, ops) and branded dashboards for turbopuffer namespaces. Runs over the somoore/turbopuffer Steampipe plugin.
- Host: GitHub
- URL: https://github.com/somoore/powerpipe-turbopuffer-security-benchmark
- Owner: somoore
- Created: 2026-07-07T19:05:58.000Z (18 days ago)
- Default Branch: main
- Last Pushed: 2026-07-07T20:15:50.000Z (17 days ago)
- Last Synced: 2026-07-07T21:09:14.259Z (17 days ago)
- Topics: compliance, powerpipe, powerpipe-mod, security, sql, steampipe, turbopuffer, vector-search
- Language: Puppet
- Homepage: https://github.com/somoore/steampipe-plugin-turbopuffer
- Size: 307 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README

# turbopuffer Security Benchmark Mod for Powerpipe
Run individual tenant-isolation, data-residency, encryption, schema-hygiene and operations controls — or the full security benchmark — across your [turbopuffer](https://turbopuffer.com) namespaces using [Powerpipe](https://powerpipe.io) and [Steampipe](https://steampipe.io).
> Unofficial community project. Not affiliated with or endorsed by turbopuffer inc. All read-only.
Run checks in a dashboard:

## Why
turbopuffer's own permissions documentation is explicit: row/document-level access control is the **application's** responsibility, implemented via attribute filters. There is no built-in RBAC below the API-key level. That's a reasonable architectural choice — and it means every turbopuffer customer is one missing schema attribute or one non-filterable field away from cross-tenant retrieval. Nothing audits that today. This does.
## What gets checked
| # | Control | Severity | Signal |
|---|---------|----------|--------|
| 1 | `tenant_isolation_acl_attributes_present` | critical | Tenant namespaces define the ACL attributes your filters depend on |
| 2 | `tenant_isolation_acl_attributes_filterable` | critical | …and those attributes are actually `filterable` (BM25 fields aren't, by default) |
| 3 | `tenant_isolation_namespace_naming` | medium | Namespaces match the naming convention other controls key off |
| 4 | `tenant_isolation_canary_document_present` | high | Honeytoken doc seeded per namespace (alert on its retrieval in your app logs) |
| 5 | `residency_approved_regions_only` | high | Namespaces only in approved regions |
| 6 | `residency_eu_namespaces_in_eu_regions` | critical | EU-tagged namespaces hosted in EU regions |
| 7 | `encryption_cmek_on_sensitive_namespaces` | high | Prod/PII namespaces use customer-managed keys |
| 8 | `encryption_cmek_keys_approved` | medium | CMEK keys come from the approved key inventory |
| 9 | `hygiene_sensitive_attribute_names` | high | No `ssn`/`card_number`/`api_key`-style attributes next to your vectors |
| 10 | `hygiene_sensitive_attributes_not_search_indexed` | high | Sensitive attrs aren't FTS/regex/glob/fuzzy-indexed (exposure amplification) |
| 11 | `hygiene_schema_drift_across_environments` | medium | `prod-x` and `staging-x` schemas match |
| 12 | `hygiene_empty_namespaces` | low | No abandoned empty namespaces |
| 13 | `ops_stale_namespaces` | medium | Every namespace has an owner writing to it (`updated_at` recency) |
| 14 | `ops_index_lag` | medium | No unindexed WAL bytes — recent writes are searchable, not silently missed |
| 15 | `ops_oversized_namespaces` | medium | Single-namespace blast radius under threshold |
| 16 | `ops_namespace_sprawl` | low | Total namespace count within budget |
Everything is tunable in `variables.pp`.
## Getting Started
### Installation
Install [Powerpipe](https://powerpipe.io/downloads), or use Brew:
```bash
brew install turbot/tap/powerpipe
```
This mod requires [Steampipe](https://steampipe.io) with the [turbopuffer plugin](https://github.com/somoore/steampipe-plugin-turbopuffer) as the data source. Install Steampipe (https://steampipe.io/downloads), or use Brew:
```bash
brew install turbot/tap/steampipe
```
The plugin has [shipped its first release](https://github.com/somoore/steampipe-plugin-turbopuffer/releases) and is submitted to the Steampipe Hub, but isn't listed there yet — so `steampipe plugin install somoore/turbopuffer` won't resolve until that goes live. Until then, install from the GitHub release:
```bash
# darwin/arm64 shown; swap for your OS/arch from the releases page
curl -L -o turbopuffer.plugin.gz \
https://github.com/somoore/steampipe-plugin-turbopuffer/releases/latest/download/steampipe-plugin-turbopuffer_darwin_arm64.gz
gunzip turbopuffer.plugin.gz
mkdir -p ~/.steampipe/plugins/local/turbopuffer
mv turbopuffer.plugin ~/.steampipe/plugins/local/turbopuffer/turbopuffer.plugin
chmod +x ~/.steampipe/plugins/local/turbopuffer/turbopuffer.plugin
```
Once Hub listing lands, switch back to `steampipe plugin install somoore/turbopuffer` and use `plugin = "somoore/turbopuffer"` in your connection config below.
Configure your connection with a turbopuffer API key and the regions to scan (see the [plugin's sample config](https://github.com/somoore/steampipe-plugin-turbopuffer/blob/main/config/turbopuffer.spc) and [docs](https://github.com/somoore/steampipe-plugin-turbopuffer)):
```bash
curl -o ~/.steampipe/config/turbopuffer.spc \
https://raw.githubusercontent.com/somoore/steampipe-plugin-turbopuffer/main/config/turbopuffer.spc
$EDITOR ~/.steampipe/config/turbopuffer.spc # api_key + regions
# if you installed manually above, also change: plugin = "local/turbopuffer"
```
Finally, install the mod (only needed if you're pulling this mod into another workspace as a dependency — skip this if you've cloned this repo directly, just `cd` into it):
```bash
mkdir dashboards
cd dashboards
powerpipe mod init
powerpipe mod install github.com/somoore/powerpipe-turbopuffer-security-benchmark
```
> Until the plugin is listed on the Hub, `mod install` fails with a plugin-version error (manually-installed plugins report their version as `local`, which can't satisfy any `min_version` check). `powerpipe benchmark run` and `powerpipe server` still work fine against a direct clone — that error is only a blocker for the dependency-install path above.
### Browsing Dashboards
Start Steampipe as the data source:
```bash
steampipe service start
```
Start the dashboard server:
```bash
powerpipe server
```
Browse and view your dashboards at **http://localhost:9033**.
Two branded dashboards ship with the mod:
- **turbopuffer: Security Posture** — box-drawn hero and Step 1/2/3 panels echoing the onboarding page, posture cards that flip coral on alert, and a Largest Namespaces table that drills into…
- **turbopuffer: Namespace Detail** — a namespace selector, size/freshness/encryption cards, a **Tenant Isolation: ready / NOT enforceable** verdict card (required ACL attributes present *and* filterable), and the full attribute schema with search-amplification flags.
### Running Checks in Your Terminal
Instead of running benchmarks in a dashboard, you can run them in your terminal with the `powerpipe benchmark` command:
List available benchmarks:
```bash
powerpipe benchmark list
```
Run the benchmark:
```bash
powerpipe benchmark run turbopuffer_security \
--var 'required_acl_attributes=["tenant_id"]' \
--var 'approved_regions=["gcp-us-central1"]'
```
Different output formats are also available — for more information see [Output Formats](https://powerpipe.io/docs/reference/cli/benchmark#output-formats).
## The data source
This mod queries the tables exposed by the [turbopuffer Steampipe plugin](https://github.com/somoore/steampipe-plugin-turbopuffer):
| Table | One row per | Notable columns |
|-------|-------------|-----------------|
| `turbopuffer_namespace` | namespace × region | `approx_row_count`, `approx_logical_bytes`, `created_at`, `updated_at`, `encryption_mode`, `encryption_key_name`, `index_status`, `schema` |
| `turbopuffer_namespace_attribute` | schema attribute | `type`, `filterable`, `full_text_search`, `regex`, `glob`, `fuzzy`, `vector_index`, `sparse_vector_index` |
| `turbopuffer_document` | document (requires `namespace` qual) | `id`, `attributes` — vectors always excluded; built for canary lookups, not export |
| `turbopuffer_namespace_recall` | recall evaluation (requires `namespace` qual) | `avg_recall`, `avg_ann_count`, `avg_exhaustive_count` — index-integrity signal |
| `turbopuffer_region` | configured region | `region`, `endpoint` — join anchor for residency queries |
Because it's all SQL in Steampipe, these join against the other 150+ plugins: put turbopuffer residency next to `aws_s3_bucket` residency in one report, or join namespaces against a `tenants.csv` to catch orphaned tenants.
## Grounding & honesty notes
- Endpoint paths and response fields were **verified against the official `turbopuffer-go/v2` client and the [turbopuffer OpenAPI spec](https://github.com/turbopuffer/turbopuffer-openapi)**, then confirmed against a live account. The metadata response is what makes CMEK, staleness, and index-lag controls real rather than aspirational.
- **Compiled, tested, and run against a live account** (0 errors against seeded live data, load-tested to 1,200+ namespaces).
- **The control-plane gap**: turbopuffer's public API is data-plane only. API keys, permissions, org membership and billing are dashboard-only — that's why there's no `turbopuffer_api_key` table. Track what you can't check; that list is the roadmap.
## Open Source & Contributing
This repository is published under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). [Steampipe](https://steampipe.io) and [Powerpipe](https://powerpipe.io) are products produced by [Turbot HQ, Inc](https://turbot.com); this mod is an independent community project and is not affiliated with Turbot or turbopuffer inc.
turbopuffer logos are used under turbopuffer's [brand guidelines](https://turbopuffer.com/press).
## Get Involved
**[Join #powerpipe on Slack →](https://turbot.com/community/join)**