Vectasec · Concepts
Security model
How Vectasec keeps collection read-only, isolates tenants in Postgres, stores credentials in Vault, authenticates API callers and bounds the collector.
On this page
This page covers what Vectasec reads, how tenants are kept apart, how callers are authenticated and where credentials live. It also lists what to set before you expose the engine.
Read-only collection#
Connectors read. They don't change configuration or data on the systems they scan. For the most common connectors:
- AWS:
List*,Get*andDescribe*calls, plussts:AssumeRolewhen you give the connection a role to assume. - Kubernetes: LIST and GET only. Service-account token Secrets are reduced to metadata before anything is stored.
- Kafka: AdminClient describe and list calls.
- RabbitMQ: Management API GETs only. One of them is a
GET /api/whoamias the defaultguestuser, which checks whether that account is limited to loopback. - Redis:
INFO,CONFIG GETon an allow-list of settings, ACL user reads,CLIENT LISTandACL LOG. - MCP: discovery and
tools/list, nevertools/call. Active probes run only if you setactive_probes.
Connectors don't read message payloads or the values held in caches and key-value stores. Discovery scans only the targets you declare and sends only pre-authentication bytes, never credentials. It refuses public addresses unless you set allow_public, stops at 1,024 hosts per scan and never contacts ports 9100–9107, 1414–1416, 515 or 631.
Tenant isolation in Postgres#
Every tenant table has row-level security enabled and forced. The console uses the authenticated role. That role gets SELECT policies scoped to your tenants, and no INSERT, UPDATE or DELETE policies at all. Changes to tenant data go through the engine API. The only writes the console makes directly are two narrow database functions: creating your own organization at sign-up and recording your own last-seen time.
The engine's database role bypasses RLS, so every engine statement filters on tenant_id explicitly. Keep DATABASE_URL and the Supabase service-role key on the engine side only.
API authentication#
The engine checks three paths in order. When none matches, it returns 401.
The Collector's heartbeat, jobs and results endpoints accept only a short-lived HMAC token over {tenant, collector, exp}. The Collector gets that token from /collector/enroll in exchange for its enrollment token.
Roles and audit#
Each member's role in the organization sets what they can do:
- viewer: read only.
- analyst or editor: scans, triage, suppressions, connections and attestations.
- admin or owner: all of that, plus integrations, routing rules and members.
Every mutation needs an actor and writes an audit-log row in the same transaction. Updates to the audit log are rejected by a trigger.
With the service token, the engine trusts the console to name the acting user, then looks up that user's role itself. Keep the token on the console's server side. When the deployment serves one tenant, pin the token with VECTASEC_ENGINE_TOKEN_TENANT.
Platform operators, listed in a separate operator table, act as admin in any tenant when they sign in with their own JWT. The browser can't write that table. On the service-token path this elevation is off unless you set VECTASEC_ALLOW_SERVICE_SUPERADMIN.
Credentials#
- Fields a connector declares secret, such as
rabbitmq.passwordoraws.secret_access_key, are stored as one Supabase Vault secret per connection. The connection refers to it. - Secrets are merged into memory only at scan or test time, and they are never logged. Audit rows record config keys, not values.
- Deleting a connection deletes its secret in the same transaction. Scan-queue (pgmq) payloads carry the public config only.
- Integration secrets are held in Vault too: webhook URLs, signing secrets, Jira and SIEM tokens.
- Non-human identity records hold credential metadata, never values. A secret found in an IaC file is kept as a 12-hex-character SHA-256 fingerprint plus its length.
Collector trust boundary#
Without a Collector, the engine connects to your systems directly with credentials from Vault. With a Collector:
- Outbound only. It opens no listening port and polls the control plane over HTTPS.
- Credentials stay local.
targets.jsoncan reference them as${ENV_VAR}, so the file holds no secrets. They go only to the connector that dials your system. - Tokens stay protected. The control plane stores only a SHA-256 hash of the enrollment token, and the Collector writes only that hash to its state file. The service token is valid for one hour and lives in memory only.
- Jobs can't redirect it. A job names a target you configured locally. It can't supply a host or a credential.
- Redaction runs last. Before anything leaves, redaction scrubs credential values, credential-shaped keys, URL userinfo and PEM private keys. Log records are scrubbed too.
- Raw config stays local. The raw resource configuration never leaves.
vectasec-collector previewprints the exact payload without contacting the control plane.
Some detail does leave, by design. Each result carries the target's connection settings with credentials redacted, such as host, port and TLS flags. Findings quote the config values a rule read. Resource labels can include internal hostnames. Run preview to see all of it before you enroll.
Outbound notifications#
These rules apply to the HTTP destinations: Slack, Teams, webhook, Jira and SIEM.
- Only
httpandhttpsURLs are accepted. - Destinations that resolve to link-local or metadata addresses are always refused.
- Private and loopback destinations are refused unless you set
VECTASEC_ALLOW_PRIVATE_NOTIFY_TARGETS=1. - Webhooks can be signed. Set
hmac_secret, and each request carries an HMAC-SHA256 of its body inX-VectaSec-Signature: sha256=<hex>.
AI triage#
AI triage is optional. With no provider key, a deterministic summary runs and nothing goes to a model. With a key, the provider receives the finding's rule, title, severity, resource and system type, plus up to 25 of its most recent distinct observations, each capped at 2,000 characters.
- Observations are fenced in
<observation>elements as data, never instructions. - The output must cite at least one numbered observation. A citation to an observation that wasn't sent discards the whole output, and the deterministic summary runs instead.
- Postgres refuses to commit uncited output.
- Priority is clamped to a severity floor, so text inside a scanned system can't downgrade a critical.
- Findings lists sort on deterministic severity, not AI priority.
Hardening checklist#
Before anything you don't control can reach the engine, work through this list. Deployment shows where each setting goes.
- Leave
VECTASEC_DEV_TRUST_HEADERSandVECTASEC_ALLOW_SERVICE_SUPERADMINunset. - Set a long random
VECTASEC_ENGINE_TOKEN, and give it only to the console's server side. For a single tenant, addVECTASEC_ENGINE_TOKEN_TENANT. - Set
SUPABASE_URLon the engine so it can verify user JWTs. - Set
VECTASEC_COLLECTOR_TOKEN_SECRETto its own random value. Otherwise the signing key is derived fromDATABASE_URL. - Keep the default
127.0.0.1bind, or put TLS and a network policy in front before you widenENGINE_HOST. SetENGINE_CORS_ORIGINSto your console's origin. - Never give the console
SUPABASE_SERVICE_ROLE_KEYorDATABASE_URL. - Leave
VECTASEC_ALLOW_PRIVATE_NOTIFY_TARGETSunset unless the engine must notify its own network. - For the Collector, use
VECTASEC_ENROLL_TOKEN_FILE, keepVECTASEC_VERIFY_TLSat its default oftrueand leaveVECTASEC_ALLOW_INSECURE_CONTROL_PLANEunset. Run it with a read-only filesystem, all capabilities dropped andno-new-privileges, and allow egress only to the control plane and your targets. - Run
vectasec doctor --verify-ledgerregularly.
Current limits#
- No SSO, SAML or SCIM. Sign-in is email and password, or Google.
- Collector authentication is server TLS plus a bearer token, not mutual TLS.
- Container images are not signed yet.
- Collector enrollment tokens can't be issued from the console or the API yet.
- The self-hosted preview bundle (Docker Compose and a Helm chart) is a preview: its configuration validates, but the stack hasn't been booted yet.
Next steps#
- Findings, evidence and compliance: the evidence ledger and how controls are evaluated.
- Run a collector in your network: configure targets, preview the payload and enroll.
- Deployment: where each setting on this page lives.