1. What this component is, honestly
The agent is a DaemonSet. It runs on every node you schedule it to, mounts host log directories, and sends data outbound. That places it in the same risk class as an EDR sensor or any node-level log forwarder, and it deserves the scrutiny you would give one.
Three properties do most of the risk reduction:
- Its Kubernetes RBAC is read-only metadata, and it never reads Secrets.
- Its outbound destinations are enumerable and configurable, and can be reduced to zero.
- Sensitive fields can be redacted inside your cluster, before any byte leaves.
2. What it can do in your cluster (RBAC)
Render the manifests yourself. This contacts no Sasquatch service and installs nothing:
helm template sasquatch-agent oci://registry.sasquatchlabs.io/sasquatch-agent-chart \
--version <version> \
--namespace sasquatch \
> rendered.yaml
Then read rendered.yaml directly. The complete cluster-scoped permission set is:
| API group | Resources | Verbs | Gated on |
|---|---|---|---|
core ("") | pods | get, list, watch | podMetadata.enabled |
apps | replicasets | get, list, watch | podMetadata.enabled |
batch | jobs | get, list, watch | podMetadata.enabled |
core ("") | events | get, list, watch | kubernetesEvents.enabled |
Plus one namespace-scoped Role, only when kubernetesEvents.enabled:
| API group | Resources | Verbs |
|---|---|---|
coordination.k8s.io | leases | get, create, update |
That is the entire set. Specifically, the agent has no permission to:
- read
secretsorconfigmaps create,update,patch, ordeleteany workloadexecinto or attach to pods- access the Kubernetes API as any identity other than its own ServiceAccount
- delete leases (update-only, so it cannot force-steal leadership)
The pod-metadata permissions exist to turn a container ID into human-readable
namespace / deployment / pod labels. Set podMetadata.enabled=false
and kubernetesEvents.enabled=false and the agent requires
no ClusterRole at all — it will still ship logs, with less useful labelling.
Verify the claim rather than believing it:
grep -A20 'kind: ClusterRole' rendered.yaml
3. Pod security posture — including where our default is not the hardened one
We would rather you hear this from us than find it in review.
The chart's default runs the agent as root. In values.yaml:
securityContext:
runAsUser: 0
readOnlyRootFilesystem: false
The reason is specific and not a shortcut: on most clusters, the container log files
under /var/log/containers are owned by root with permissions
that deny other users. An agent that cannot read them collects nothing.
The container image itself does not require root. It is built with a
dedicated sasquatch user and declares USER sasquatch. Root is
a chart default for compatibility, not an image requirement.
To run non-root, if your node log permissions allow it:
securityContext:
runAsUser: 65534
readOnlyRootFilesystem: true
Test this in a non-production cluster first. If the node's log file modes deny
nobody, the agent will start and collect nothing — a silent failure
mode, which is exactly why it is not the default. Verify with a log volume check after
rollout, not just pod readiness.
Regardless of the root setting, the container always gets:
| Control | Value |
|---|---|
allowPrivilegeEscalation | false |
capabilities.drop | [ALL] |
privileged | never set |
| host network / PID / IPC | not used |
runAsNonRoot | true whenever runAsUser != 0 |
Host mounts
| Path | Mode | Purpose |
|---|---|---|
/var/log/containers | read-only | the container log files being collected |
/var/lib/sasquatch-agent/spill | read-write | compressed chunks buffered during an upload outage |
/var/lib/sasquatch-agent (tail state) | read-write | file tail offsets, so a restart does not re-send or skip |
/tmp | emptyDir (tmpfs, 512Mi) | in-memory buffers; never touches disk |
The read-write host paths hold only the agent's own state. Set
spill.hostPathEnabled=false to move spill to tmpfs and eliminate the
write-capable host mount entirely — at the cost of losing buffered data on pod
restart during an upload outage. That is a durability-vs-surface tradeoff and it is
yours to make.
4. Supply chain — verify the image before you trust it
Every released image is signed with Sigstore cosign using GitHub OIDC (keyless, publicly logged to the Rekor transparency log) and carries a Syft-generated SPDX SBOM attestation.
Verify the signature:
cosign verify \
--certificate-identity-regexp 'https://github\.com/SasquatchLabsInc/core/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/sasquatchlabsinc/sasquatch-agent-s3:<version>
Pull the SBOM and run it through your own vulnerability scanner:
cosign verify-attestation --type spdxjson \
--certificate-identity-regexp 'https://github\.com/SasquatchLabsInc/core/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/sasquatchlabsinc/sasquatch-agent-s3:<version> \
| jq -r '.payload' | base64 -d | jq '.predicate' > sasquatch-agent.spdx.json
grype sbom:sasquatch-agent.spdx.json
Scan the image directly as well — do not take our CI's word for it:
trivy image ghcr.io/sasquatchlabsinc/sasquatch-agent-s3:<version>
Base images: rust:1-slim-bookworm (build stage),
debian:bookworm-slim (runtime). Trivy runs on every release in our
pipeline, but your scanner and your policy thresholds are the ones that matter for
your risk acceptance.
Known limitations, stated up front:
- The SBOM attestation is currently generated for the
agent-s3variant as the representative build. Thegcsandazurevariants differ only by a Cargo feature flag for the storage backend. Per-variant SBOMs are on our roadmap. - We publish cosign signatures and SBOM attestations, but not yet SLSA build provenance attestations.
Images are served through registry.sasquatchlabs.io, an authenticated proxy
in front of GHCR. Authentication uses your sqk_ API key. If your policy
requires images to come from your own registry, mirror them and override
image.repository.
5. Data flow — exactly what leaves your cluster
All outbound connections are HTTPS on 443. There are no plaintext destinations and no non-standard ports.
Sasquatch-operated endpoints
| Destination | Purpose | Default | Frequency |
|---|---|---|---|
api.sasquatchlabs.io | Tenant config, compression dictionaries, routing configs | enabled | dictionary poll 300s |
retrieve.sasquatchlabs.io | Compression training artifacts (L1/L2 dictionaries), Tap Out | enabled | training poll 300s |
api.sasquatchlabs.io (operator telemetry) | Counts-only agent health telemetry | disabled | 60s when enabled |
relay.sasquatchlabs.io | Optional hot-path relay | disabled | only if configured |
Customer-controlled destinations
| Destination | Purpose | Default |
|---|---|---|
| Your S3 / GCS / Azure Blob / R2 / MinIO bucket | Compressed cold-storage chunks | upload.mode: local — you configure the target |
| Your SIEM or observability backend | Hot-path forwarding (Datadog, Splunk HEC, Loki, Honeycomb) | you configure the target |
Your log data goes to storage and destinations you own. The Sasquatch-operated endpoints above carry configuration, compression dictionaries, and — only if you opt in — counts-only health telemetry. They are not the path your log content takes.
Inbound listeners (all opt-in, all disabled by default)
If enabled, these bind 0.0.0.0 and should be governed by a NetworkPolicy:
- OTLP gRPC and HTTP receivers (traces, metrics)
- Admin HTTP:
/health,/ready,/metrics - Loki push endpoint
- Prometheus remote-write endpoint
Keeping traffic inside your account
In the BYOC deployment model the control plane runs inside your own cloud account, so neither data nor configuration traffic crosses into Sasquatch-operated infrastructure. Operator telemetry is off by default in every deployment model and only sends counts, never log content, when explicitly enabled.
Recommended egress policy
If you restrict egress by default, allow only what you use:
# NetworkPolicy egress allow-list (SaaS mode, cold storage to S3)
- api.sasquatchlabs.io:443
- retrieve.sasquatchlabs.io:443
- <your-bucket-endpoint>:443
- kube-dns / CoreDNS
In BYOC, the first two point at your own control plane rather than ours.
6. Sensitive data handling
Redaction runs inside your cluster, in the agent, positioned post-enrichment, pre-compression, and pre-hot-forward. Redacted fields therefore never reach the cold-storage chunk or any hot destination — not merely masked at query time.
| Operation | Behaviour |
|---|---|
redact | drop the field entirely |
rename | move to a different key |
mask | regex-based, keep-last-N |
hash | tenant-salted SHA-256 |
Fail-closed guarantee
Destructive PII operations require a configured KMS-backed seal hook. Without one, the agent refuses to apply the rules — it rejects the routing config, or exits fatally at startup if such rules were already active. It does not silently continue with redaction disabled.
This matters for your threat model: a compromised or misconfigured control plane cannot
push a rule set that quietly turns redaction off, nor can it push destructive transforms
that the agent lacks the key material to seal. Opting out is possible only via an
explicit server-side bypass flag that is audit-logged with a stated reason.
Seal configuration is seal.enabled: false by default and supports AWS KMS,
Azure Key Vault, and GCP KMS. For production, prefer seal.existingSecret so
KMS credentials stay in your operator-managed Secret and never enter
values.yaml or git.
Related default: query.piiPreserveOriginal: false — strict mode. The
original line is overwritten rather than preserved, so a user cannot recover a redacted
line through a crafted query.
7. A reviewer's checklist
Run in order. Nothing here requires trusting us.
helm template ...renders offline; read every ClusterRole and Role.- Confirm no
secretsaccess and no write verbs on workloads. cosign verifysucceeds against the exact tag you intend to deploy.- Pull the SBOM attestation; scan it with your own tooling against your thresholds.
trivy imagethe tag independently.- Decide root vs. non-root; if non-root, verify log volume after rollout, not just pod readiness.
- Decide whether
spill.hostPathEnabledstays true. - Enumerate egress; apply a NetworkPolicy allow-list restricted to the destinations in section 5.
- Deploy to a non-production cluster; capture actual egress with your CNI flow logs and confirm it matches section 5.
- Configure and test PII rules; verify redaction in the destination, not just in config.
- Confirm the seal hook fails closed by deploying a destructive rule with
seal.enabled: false.
Step 9 is the one we most encourage. Do not take our destination table on faith — observe the traffic and confirm it matches.
8. Getting more
Certifications, audit reports, penetration-test summaries, completed security questionnaires, and architecture detail requiring an NDA are available in the trust center.
To report a vulnerability, email support@sasquatchlabs.io. We operate a 90-day coordinated disclosure window and a safe-harbor commitment for good-faith research.