tailscale2otel

module
v4.0.0-...-8d9cc8d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2026 License: Apache-2.0

README

tailscale2otel — Tailscale → OpenTelemetry & Prometheus exporter

Release CI Container Helm chart Go Reference OpenSSF Scorecard License

A single Go binary that turns your Tailscale tailnet into OpenTelemetry metrics, logs and traces over OTLP — or a Prometheus /metrics endpoint, or both at once. Network flow logs, configuration audit logs, device fleet health, key expiry, ACL risk, and tailscaled per-node metrics, exported to Grafana Cloud or any OTEL backend. Headscale is supported too.

📖 Full documentation: m7kni.io/tailscale2otelGetting started · Installation · Configuration · Metrics catalog

255 metrics + 15 log-event types across 16 collectors
18 Tailscale API endpoints consumed polled, streamed, or webhook-driven
123 shipped rules 100 alert + 23 recording, Grafana-managed
1 Grafana dashboard flagship, 10 tabs, v2 dynamic (Grafana 13+)
OTLP push (gRPC/HTTP) and/or a Prometheus pull endpoint

Why this exists

Tailscale — the WireGuard-based mesh VPN — exposes a genuinely rich observability surface: network flow logs, configuration audit logs, a detailed device inventory, users, keys, DNS, ACL policy, device posture. But it has no Prometheus endpoint of its own, and it streams logs only to SIEM/storage sinks like Splunk or S3. The existing Tailscale exporters cover a slice of the device API and stop there.

tailscale2otel covers the whole surface and models it properly: semantic-convention-compliant OTEL telemetry, with cardinality control that makes flow logs survivable on a metrics backend.

Things nothing else does
  • Network flow logs as both metrics and logs. Low-cardinality aggregate counters (tailscale.network.io / .packets / .flows) for dashboards and alerting, plus full-fidelity per-connection records as OTEL logs for drill-down — with a top-N rollup (busiest 500 pairs, rest folded to __other__), opt-in port dimensions, and IANA service-name attribution so dst.port: 443 becomes https. This is the feature that usually makes flow logs unaffordable, and it is the reason this project exists.
  • Configuration audit logs → structured OTEL logs + a curated, security-categorized change counter, so you can alert on high-value tailnet changes without ingesting the whole stream.
  • Central tailscaled node-metrics polling. Scrapes each node's native client-metrics endpoint (:5252) from one place instead of deploying a scraper per node — with automatic target discovery from the devices API (tag include/exclude, online-only, address family). Emits both the raw tailscaled_* series and 8 curated tailscale.node.* metrics with folded low-cardinality attributes.
  • Full API-surface coverage — not just devices. Users, auth keys / OAuth clients / API tokens (with expiry), tailnet settings, DNS, ACL policy (scored for structural risk: wildcards, unrestricted rules, auto-approvers, SSH wildcards), device posture / MDM integrations, Tailscale Services, webhook endpoints, contacts, log-stream delivery health, and OAuth apps.
  • Four ingestion paths into one pipeline — poll the API, receive Tailscale's log stream on a built-in Splunk-HEC-compatible receiver, read Tailscale's flow-log export straight out of an S3-compatible bucket, or take real-time HMAC-verified webhooks. All four feed the same processors.
  • Offline GeoIP and ASN enrichment of external peers. Optional, from MaxMind .mmdb files on local disk — no hosted lookup service, no per-address network call on the hot path. Country and continent are bounded and can go on flow metrics; the autonomous system (and, with a City database, locality and coordinates) ride the flow logs, where a breakdown costs nothing. Databases hot-swap on a schedule, with a built-in MaxMind updater if you want one. Tailnet addresses are never geolocated.
  • Multi-tailnet / MSP mode — one process observing N tailnets, each with its own credentials, and tailscale.tailnet as a real label on every signal (no target_info join required).
  • PII redaction on by default — 13 opt-out categories covering emails, user IDs, hostnames, IPs, node IDs and free-text detail, applied to metric attributes, log bodies and span attributes.
  • API drift CI. Tailscale's API "may change or break without notice", so a decode-fuzz lane gates every PR and three scheduled lanes diff the live OpenAPI spec, track the upstream client library, and hit the real API read-only. See API drift CI.

Quick start

Docker
docker run --rm \
  -e TS2OTEL_TAILSCALE__TAILNET=example.com \
  -e TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_ID=<client-id> \
  -e TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET=<client-secret> \
  -e TS2OTEL_OTLP__GRAFANA_CLOUD__INSTANCE_ID=<stack-id> \
  -e TS2OTEL_OTLP__GRAFANA_CLOUD__TOKEN=<token> \
  ghcr.io/rknightion/tailscale2otel:latest

No config file needed — every setting has a TS2OTEL_* environment variable. Mount a YAML file and pass -config /etc/tailscale2otel/config.yaml if you prefer.

Kubernetes (Helm)

Put the credentials in a Secret first, then point the chart at it. They never reach your shell history, and never pass through Helm at all:

cat > creds.env <<'EOF'
TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_ID=...
TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET=...
TS2OTEL_OTLP__GRAFANA_CLOUD__INSTANCE_ID=...
TS2OTEL_OTLP__GRAFANA_CLOUD__TOKEN=...
EOF
chmod 600 creds.env

kubectl create secret generic tailscale2otel-creds --from-env-file=creds.env
rm creds.env

helm install tailscale2otel oci://ghcr.io/rknightion/charts/tailscale2otel \
  --set-string config.tailscale.tailnet=example.com \
  --set-string existingSecret=tailscale2otel-creds

Do not pass a credential as an inline --set secret.<KEY> value: it lands in your shell history and is visible in ps to every other user on the machine. scripts/check_doc_commands.py fails CI if any documented command does.

See Installation for docker-compose, prebuilt binaries (Linux/macOS/Windows × amd64/arm64), and the full chart values.

Binary
go build -o tailscale2otel ./cmd/tailscale2otel
cp config.example.yaml config.yaml   # then edit; secrets stay in env vars
./tailscale2otel -config config.yaml

./tailscale2otel -version                      # print version and exit
./tailscale2otel -validate -config config.yaml # lint a config without starting
No backend? Run it locally

Set TS2OTEL_OTLP__PROTOCOL=stdout to print metrics and logs to the console.

Where the telemetry goes

  • OTLP push (otlp.protocol: grpc|http) with first-class Grafana Cloud support — set otlp.grafana_cloud.{instance_id,token} and the Basic-auth header is built for you. Full TLS/mTLS knobs. Metrics and logs always; traces are opt-in (tracing.enabled) for the exporter's own self-observability, with exemplars linking API-duration histograms to the originating span.
  • Prometheus pull endpoint (prometheus.enabled, off by default) — GET /metrics on its own dedicated listener (default :2112), served alongside OTLP push, with optional bearer/basic auth and TLS. Use it if you already run Prometheus and don't want an OTLP pipeline.
  • stdout for local debugging.

OTLP→Prometheus naming: query the normalized name. Dots become underscores, monotonic counters gain _total, units suffix (By_bytes, s_seconds), and a unit-1 gauge gains _ratio — so tailscale.network.iotailscale_network_io_bytes_total. The full mapping is in the metrics catalog.

Collectors

Collector Cadence Emits
devices 60s online/last-seen/key-expiry/update gauges, NAT & connectivity quality, per-DERP latency, subnet routes, tailnet lock, fleet hygiene roll-ups. Feeds the enrichment cache
flowlogs 60s aggregated traffic counters + per-connection flow logs
auditlogs 60s audit-event logs + a categorized change counter
users 300s user/role/status counts, per-user device & connection gauges, outstanding invites
keys 300s expiry gauges and counts across auth keys, OAuth clients and API tokens
oauth_apps 300s OAuth-application inventory (alpha API; idles silently where unavailable)
settings 600s tailnet feature-toggle gauges
acl 600s ACL size, change detection (by ETag), structural risk scoring
dns 600s nameserver / search-path / split-zone counts, MagicDNS flag
contacts 600s contact verification status (the email itself is never emitted)
webhooks 600s webhook-endpoint inventory + per-endpoint subscription counts
posture_integrations 600s MDM/EDR integration counts, sync health, matched devices
log_stream 600s Tailscale's own SIEM-sink delivery health + delivery counters
services 600s Tailscale Services (VIP) inventory — counts, ports, opt-in backing hosts
node_metrics 60s (opt-in) scrapes tailscaled /metrics endpoints; see above

Each can be disabled or re-tuned. Under provider: headscale the Tailscale-only collectors auto-disable and a reduced set (devices, users, keys, ACL, node-metrics) runs.

Device enrichment depends on the devices collector — flow/audit IP→name resolution silently degrades to unknown/external without it.

Logs: poll, stream or object store — pick one

Both flowlogs and auditlogs take a source of poll (default), stream, objectstore or both. Tailscale exports each log type to object storage independently, so each has its OWN destination (collectors.flowlogs.objectstore / collectors.auditlogs.objectstore) and nothing is inherited between them. Pick exactly one method per log type — running two risks double-counting, cross-source de-dup is only a best-effort failsafe, and the exporter WARNs at startup when it sees this.

# Poll: tailscale2otel pulls on a schedule (interval/lag/initial_lookback/max_window apply).
flowlogs: { enabled: true, source: poll, interval: 60s, lag: 120s, initial_lookback: 5m, max_window: 1h }

# Stream: Tailscale pushes to the built-in HEC receiver (the window fields are ignored).
flowlogs: { enabled: true, source: stream, log_mode: per_connection }

# Object store: read the export Tailscale writes to S3. No API quota, and the cheapest path for a
# busy tailnet. Credentials come from the ambient chain (env, IRSA, instance profile).
flowlogs:
  enabled: true
  source: objectstore
  objectstore: { endpoint: https://s3.eu-west-2.amazonaws.com, region: eu-west-2, bucket: my-flow-logs }

Object-store delivery is at-least-once. With the file checkpoint store, successful object identities and failed-object gaps survive restart; transient failures retry with bounded backoff, while invalid compressed objects are quarantined for operator acknowledgement. One object is all-or-nothing — every row is decoded before any is committed, so a mid-object failure emits nothing rather than a partial prefix — but the object as a unit replays if the process dies between emission and the checkpoint write. OTLP/backend acknowledgement is outside this boundary.

Backfill has a hard ceiling of 14 day partitions — today plus the previous 13 days — under the default layout: partitioned, whatever initial_lookback says. It is permanent, not per-cycle: one cycle enumerates at most 14 day prefixes newest-first, and the cursor only moves forward, so older days are never listed and are skipped with no gap, no error and no metric. layout: flat has no partitions to cap and reaches arbitrarily far back, at the cost of more LIST requests. The exporter warns at startup when initial_lookback exceeds the ceiling. See Streaming & webhooks for the full path-by-path compatibility, delivery and durability matrix.

Checkpoints persist how far poll and object-store collectors have read. Details on all paths, receiver auth, object-gap handling, and auto_configure are in Streaming & webhooks.

Dashboards, alerts & the admin UI

  • Dashboardsdeploy/grafana/ ships two dashboards on Grafana's v2 schema (Grafana 13+): Tailnet (is my tailnet healthy — devices, network, security, policy) and Exporter health (is the exporter healthy — collection, ingestion, delivery, runtime, cost), cross-linked to each other, with dynamic rendering so a section only appears when its data is present. Grafana 13+ is a hard requirement — 12.4 accepts the file with a 200 and renders nothing, and 11.5 rejects it with the misleading Dashboard title cannot be empty. Push them with gcx resources push -f. See Dashboards.
  • Alertsdeploy/alerts/grafana-managed/ ships 100 alert rules and 23 recording rules (123 total) as rules.alerting.grafana.app manifests, one JSON per rule. Push them with gcx resources push -p deploy/alerts/grafana-managed. Every alert carries a runbook_url, and 77 of 78 link a canonical dashboard panel. See Alerts and Runbooks.
  • Admin status page — on by default at :9091. Liveness/readiness probes at /healthz and /readyz (never auth-gated), a live status page at /, and the same snapshot at /api/status.json: per-collector health, active-series cardinality with per-label breakdown, the full metrics/log catalog, discovered node targets, and a redacted config summary. Entirely self-contained — no CDN assets, so it renders on an air-gapped tailnet. Auth fails closed on a non-loopback bind with no admin.auth.token.
  • Continuous profiling is opt-in — pprof on the admin server (for Grafana Alloy to pull), or push to Pyroscope / Grafana Cloud Profiles.

Configuration

Layered, lowest precedence first: built-in defaultsoptional YAML fileenvironment variables. Every field is settable as TS2OTEL_ + the dotted key path with __ between levels:

Config key Environment variable
tailscale.auth.oauth.client_secret TS2OTEL_TAILSCALE__AUTH__OAUTH__CLIENT_SECRET
otlp.endpoint TS2OTEL_OTLP__ENDPOINT
collectors.flowlogs.interval TS2OTEL_COLLECTORS__FLOWLOGS__INTERVAL

An unrecognised TS2OTEL_* variable is logged as a WARN at startup — usually a typo.

Authentication: prefer an OAuth client (auto-refreshing, least-privilege all:read) over an API key. Keyless workload identity (OIDC token exchange, e.g. a Kubernetes projected service-account token) is also supported, and every secret has a *_file variant for Docker/Kubernetes secrets.

Full configuration reference · every TS2OTEL_* variable · config.example.yaml

Documentation

Getting started Zero to first metrics in Grafana Cloud
Installation Docker, Helm, compose, binaries
Configuration Every key, default and gotcha
Metrics catalog All 186 metrics and 13 log events
Node metrics Central tailscaled scraping
Streaming & webhooks HEC receiver and webhooks
Architecture How it fits together
Security Data handling, PII, receiver auth
Troubleshooting When it doesn't work

Development

go build ./... && go vet ./... && go test -race ./...
golangci-lint run

Small single-purpose packages under internal/: telemetry (OTEL facade), collector (scheduler/registry/checkpoints + one package per source), tsapi (Tailscale client), provider/hsapi (control-plane abstraction + Headscale), flowlog/audit (records + processors), enrich (device cache), rdns, config, and the stream/webhook receivers. Four committed files are generated — run scripts/regen-generated.sh before committing changes that touch them.

API drift CI

Tailscale's API and OpenAPI spec evolve continuously ("may change or break without notice"), which has broken decoders here before. Eight lanes guard it:

Lane When What it checks
Schema-driven decode tests every PR (gates) synthesizes payloads from the vendored OpenAPI spec + known wire quirks (numeric proto, polymorphic audit old/new) through the real decoders, plus a boundary matrix running every consumed operation against every boundary shape — null, empty container, nulled nullable fields, extreme values, an unknown enum member, an additive field, and a wrong container shape that must be rejected. Runs inside the normal go test -race ./... leg, which ci-success requires
Exploratory fuzzing every PR (advisory) go test -fuzz over the HEC envelope, HEC timestamps and the flow/audit decoders. Deliberately not required: finding a NEW crasher is nondeterministic, so gating it would let an unrelated PR randomly block merges. Each target's seed corpus runs in the gated leg above, so a KNOWN crasher still blocks
OpenAPI drift daily diffs the live spec against the vendored copy, scoped to consumed operations. Covers response fields, path/query/header parameters (requiredness, type, default, enum), the success-status set and request/response media types, classifying each as breaking, behavioral or additive
Client-lib tracking weekly builds and tests against tailscale-client-go/v2@main and @latest
Scheduled fuzzing weekly the same nine fuzz targets for 15 minutes each instead of 120 seconds, where a nondeterministic finding costs nobody a blocked merge. Opens a deduplicated tracking issue on a crasher and attaches the failing input
Live contract daily hits the real API read-only and asserts every consumed GET still decodes
Changelog review monthly reads Tailscale's changelog feed for entries that name something this exporter collects and carry no recorded verdict in spec/changelog-reviewed.json. Catches a capability announced before, or without, any OpenAPI change. Reviewing an entry means recording a verdict — including a negative one, so a surface already declined is never re-proposed
IANA registry freshness monthly regenerates the embedded IANA service-name table from the live registry and reports a diff. The committed copy has no other drift gate and its staleness is invisible at runtime — an unregistered port and a port missing from a stale table both map to no service name
Release completeness every release reads the published release back and fails when its asset manifest is short. Two releases shipped permanently incomplete behind green workflows before this existed

Scheduled lanes are advisory — they open a deduplicated tracking issue and fail the run, but never block PRs. Of the PR-time lanes, only the schema-driven decode tests gate; exploratory fuzzing does not, for the reason in its row.

The cadences and the advisory-versus-gating split in this table are asserted by internal/ci/workflowcontract_test.go, which reads the workflow files — two of these rows claimed "weekly" against daily crons until that test was added (#436).

Maintainer one-time setup
gh label create api-drift -c FBCA04
gh label create clientlib-drift -c FBCA04
gh label create live-contract -c FBCA04

The live lane stores no long-lived Tailscale key. It runs on a standard GitHub-hosted runner and mints a short-lived token from Tailscale's OAuth endpoint using a read-only (all:read) OAuth client, whose TS_OAUTH_CLIENT_ID / TS_OAUTH_CLIENT_SECRET are repo secrets. Keeping them as secrets is safe because this lane is schedule + workflow_dispatch only, so a fork PR can never run it and never reach them; the minted token is masked and lives only for that run. Set the repo variable TS_TAILNET (the tailnet name is not a secret). Missing configuration fails the lane loudly rather than self-skipping, so a misconfigured preflight cannot look green. Optionally set the ANTHROPIC_API_KEY secret for Claude enrichment on the spec-drift and live lanes; the client-lib lane never receives it by design, since it builds untrusted upstream code.

License

Apache License 2.0 — full text in LICENSE; third-party attribution and bundled notices/SBOMs in LICENSING.md.

Directories

Path Synopsis
cmd
tailscale2otel command
Command tailscale2otel polls the Tailscale API and exports OTEL metrics + logs.
Command tailscale2otel polls the Tailscale API and exports OTEL metrics + logs.
internal
aclpolicy
Package aclpolicy compiles a Tailscale network policy and decides whether an observed connection is explained by it.
Package aclpolicy compiles a Tailscale network policy and decides whether an observed connection is explained by it.
annotations
Package annotations publishes a curated, closed set of tailnet events into Grafana as annotations, so a dashboard can answer "what changed at 14:00" from tailscale2otel itself rather than from an external automation (#518).
Package annotations publishes a curated, closed set of tailnet events into Grafana as annotations, so a dashboard can answer "what changed at 14:00" from tailscale2otel itself rather than from an external automation (#518).
apistate
Package apistate models the availability of an individual Tailscale API operation, and the coverage of per-entity subrequests.
Package apistate models the availability of an individual Tailscale API operation, and the coverage of per-entity subrequests.
app
Package app wires configuration, telemetry, the Tailscale client, the device cache, and the collector scheduler into a runnable service.
Package app wires configuration, telemetry, the Tailscale client, the device cache, and the collector scheduler into a runnable service.
app/apicontract
Package apicontract is the versioning/publishing/compatibility-checking engine for tailscale2otel's read-only admin JSON API (#323): /api/status.json, /api/config.json, /api/cardinality.json, /api/flows.json, /api/events.json, and /api/flows/export.json.
Package apicontract is the versioning/publishing/compatibility-checking engine for tailscale2otel's read-only admin JSON API (#323): /api/status.json, /api/config.json, /api/cardinality.json, /api/flows.json, /api/events.json, and /api/flows/export.json.
app/eventsdata
Package eventsdata is the wire and template contract for the built-in audit/webhook event explorer (#300): Response is what /api/events.json returns, Page is the server-rendered shell of /events.
Package eventsdata is the wire and template contract for the built-in audit/webhook event explorer (#300): Response is what /api/events.json returns, Page is the server-rendered shell of /events.
app/eventshtml
Package eventshtml renders the built-in audit/webhook event explorer at /events (#300).
Package eventshtml renders the built-in audit/webhook event explorer at /events (#300).
app/flowhtml
Package flowhtml renders the built-in flow view at /flows.
Package flowhtml renders the built-in flow view at /flows.
app/flowsdata
Package flowsdata is the wire and template contract for the built-in flow view: Response is what /api/flows.json returns, Page is the server-rendered shell of /flows.
Package flowsdata is the wire and template contract for the built-in flow view: Response is what /api/flows.json returns, Page is the server-rendered shell of /flows.
app/statusdata
Package statusdata defines the data model rendered by the admin status page (internal/app/statushtml) and served verbatim as JSON at /api/status.json.
Package statusdata defines the data model rendered by the admin status page (internal/app/statushtml) and served verbatim as JSON at /api/status.json.
app/statushtml
Package statushtml renders the admin status page from a statusdata.Status.
Package statushtml renders the admin status page from a statusdata.Status.
appcatalog
Package appcatalog holds the app layer's self-observability metric descriptors (the heartbeat up gauge and the Tailscale API request/retry counters) as the SINGLE SOURCE OF TRUTH for both their emission and their documentation.
Package appcatalog holds the app layer's self-observability metric descriptors (the heartbeat up gauge and the Tailscale API request/retry counters) as the SINGLE SOURCE OF TRUTH for both their emission and their documentation.
audit
Package audit defines the Tailscale configuration audit log record types and (in processor.go) the conversion to OTEL log records and counters.
Package audit defines the Tailscale configuration audit log record types and (in processor.go) the conversion to OTEL log records and counters.
catalog
Package catalog aggregates every emitting package's in-code telemetry catalog (the metricdoc.Metric / metricdoc.LogEvent descriptors declared next to each emit site) into the single, ordered source of truth that the docs generator renders into docs/metrics.md.
Package catalog aggregates every emitting package's in-code telemetry catalog (the metricdoc.Metric / metricdoc.LogEvent descriptors declared next to each emit site) into the single, ordered source of truth that the docs generator renders into docs/metrics.md.
certreload
Package certreload serves TLS certificates that can be rotated underneath a running listener.
Package certreload serves TLS certificates that can be rotated underneath a running listener.
collector
Package collector defines the pluggable data-source model: the Collector interfaces every source implements, a Registry of enabled collectors, the checkpoint store for time-window pollers, and the Scheduler that drives them.
Package collector defines the pluggable data-source model: the Collector interfaces every source implements, a Registry of enabled collectors, the checkpoint store for time-window pollers, and the Scheduler that drives them.
collector/acl
Package acl is a snapshot collector for the tailnet ACL policy file.
Package acl is a snapshot collector for the tailnet ACL policy file.
collector/auditlogs
Package auditlogs implements the "auditlogs" window collector.
Package auditlogs implements the "auditlogs" window collector.
collector/contacts
Package contacts is a snapshot collector for the tailnet's account/support/ security contacts.
Package contacts is a snapshot collector for the tailnet's account/support/ security contacts.
collector/devices
Package devices implements the "devices" snapshot collector.
Package devices implements the "devices" snapshot collector.
collector/dns
Package dns is a snapshot collector for the tailnet DNS configuration.
Package dns is a snapshot collector for the tailnet DNS configuration.
collector/flowlogs
Package flowlogs implements the "flowlogs" polling collector: the POLL path for Tailscale network flow logs.
Package flowlogs implements the "flowlogs" polling collector: the POLL path for Tailscale network flow logs.
collector/keys
Package keys is a snapshot collector that reports Tailscale auth/API key inventory: per-key expiry time, aggregate counts grouped by type and auth sub-kind (plus revoked/invalid state), and a warning log event for keys nearing expiry.
Package keys is a snapshot collector that reports Tailscale auth/API key inventory: per-key expiry time, aggregate counts grouped by type and auth sub-kind (plus revoked/invalid state), and a warning log event for keys nearing expiry.
collector/logstream
Package logstream is a stateful snapshot collector for the tailnet's configuration/network log-streaming DELIVERY HEALTH (GET /logging/{type}/stream/status) — Tailscale's own view of whether it is successfully delivering audit/flow logs to the configured SIEM sink.
Package logstream is a stateful snapshot collector for the tailnet's configuration/network log-streaming DELIVERY HEALTH (GET /logging/{type}/stream/status) — Tailscale's own view of whether it is successfully delivering audit/flow logs to the configured SIEM sink.
collector/nodemetrics
Package nodemetrics implements a gated snapshot collector that scrapes a configured list of Prometheus-text /metrics endpoints (for example the per-node metrics tailscaled exposes) and re-emits every sample centrally through the shared telemetry.Emitter.
Package nodemetrics implements a gated snapshot collector that scrapes a configured list of Prometheus-text /metrics endpoints (for example the per-node metrics tailscaled exposes) and re-emits every sample centrally through the shared telemetry.Emitter.
collector/oauthapps
Package oauthapps is a snapshot collector reporting Tailscale OAuth application inventory: an aggregate count plus per-app scope and allowed-node-attribute cardinality (scope-sprawl signals, mirroring the keys collector's tailscale.key.scopes precedent) and an info log per app.
Package oauthapps is a snapshot collector reporting Tailscale OAuth application inventory: an aggregate count plus per-app scope and allowed-node-attribute cardinality (scope-sprawl signals, mirroring the keys collector's tailscale.key.scopes precedent) and an info log per app.
collector/objectstore
Package objectstore implements provider-neutral, multi-signal object-store ingestion.
Package objectstore implements provider-neutral, multi-signal object-store ingestion.
collector/postureintegrations
Package postureintegrations is a snapshot collector for the tailnet's device-posture integrations (MDM/EDR providers such as Intune).
Package postureintegrations is a snapshot collector for the tailnet's device-posture integrations (MDM/EDR providers such as Intune).
collector/services
Package services is a snapshot collector for the tailnet's Tailscale Services (VIP services).
Package services is a snapshot collector for the tailnet's Tailscale Services (VIP services).
collector/settings
Package settings is a snapshot collector for tailnet feature settings.
Package settings is a snapshot collector for tailnet feature settings.
collector/users
Package users is a snapshot collector that reports Tailscale user inventory: aggregate counts grouped by role/status/type, plus per-user device count, connection state, and last-seen time.
Package users is a snapshot collector that reports Tailscale user inventory: aggregate counts grouped by role/status/type, plus per-user device count, connection state, and last-seen time.
collector/webhooks
Package webhooks is a snapshot collector for the tailnet's configured webhook ENDPOINTS — an inventory of where Tailscale posts event notifications.
Package webhooks is a snapshot collector for the tailnet's configured webhook ENDPOINTS — an inventory of where Tailscale posts event notifications.
config
Package config loads, defaults, and validates the tailscale2otel configuration into typed Go structs.
Package config loads, defaults, and validates the tailscale2otel configuration into typed Go structs.
configexport
Package configexport renders the complete effective application configuration as a deterministically-keyed, redacted projection.
Package configexport renders the complete effective application configuration as a deterministically-keyed, redacted projection.
credreload
Package credreload watches outbound-telemetry credential and TLS material on disk and hot-swaps them without a process restart (#362).
Package credreload watches outbound-telemetry credential and TLS material on disk and hot-swaps them without a process restart (#362).
dedup
Package dedup provides a small, thread-safe, bounded de-duplication set.
Package dedup provides a small, thread-safe, bounded de-duplication set.
enrich
Package enrich provides an in-memory cache that maps Tailscale addresses and node IDs to device metadata, used to enrich flow and audit records with human-readable device identity.
Package enrich provides an in-memory cache that maps Tailscale addresses and node IDs to device metadata, used to enrich flow and audit records with human-readable device identity.
entityage
Package entityage holds the shared age-distribution vocabulary for tailnet entity lifecycle signals (#426).
Package entityage holds the shared age-distribution vocabulary for tailnet entity lifecycle signals (#426).
eventstore
Package eventstore retains a bounded, recent window of audit and webhook events in memory so the admin event explorer (#300) can show what happened on a tailnet without requiring a metrics/logs backend in the loop.
Package eventstore retains a bounded, recent window of audit and webhook events in memory so the admin event explorer (#300) can show what happened on a tailnet without requiring a metrics/logs backend in the loop.
flowlog
Package flowlog defines the Tailscale network flow log record types and (in processor.go) the conversion to OTEL metrics and logs.
Package flowlog defines the Tailscale network flow log record types and (in processor.go) the conversion to OTEL metrics and logs.
flowstore
Package flowstore retains recent flow activity in aggregate so the admin flow view can render a tailnet's traffic without a metrics backend in the loop.
Package flowstore retains recent flow activity in aggregate so the admin flow view can render a tailnet's traffic without a metrics backend in the loop.
flowstore/sqlitestore
Package sqlitestore is the opt-in persistent backend for the admin flow view (#294), so /flows can answer over days rather than the in-memory ring's hours and survive a restart.
Package sqlitestore is the opt-in persistent backend for the admin flow view (#294), so /flows can answer over days rather than the in-memory ring's hours and survive a restart.
geoip
Package geoip provides optional, purely LOCAL geolocation and autonomous-system enrichment of external (non-Tailscale) IP addresses, backed by MaxMind DB (.mmdb) files on disk.
Package geoip provides optional, purely LOCAL geolocation and autonomous-system enrichment of external (non-Tailscale) IP addresses, backed by MaxMind DB (.mmdb) files on disk.
hsapi
Package hsapi is a minimal read-only HTTP/JSON client for the Headscale control-plane API (/api/v1/*), authenticated with a Bearer API key.
Package hsapi is a minimal read-only HTTP/JSON client for the Headscale control-plane API (/api/v1/*), authenticated with a Bearer API key.
ingest
Package ingest defines the leaf contracts shared by ingestion paths.
Package ingest defines the leaf contracts shared by ingestion paths.
jsonbudget
Package jsonbudget bounds the memory cost of decoding one JSON response body from an upstream control-plane API.
Package jsonbudget bounds the memory cost of decoding one JSON response body from an upstream control-plane API.
k8saudit
Processor is the single emission path for tsrecorder Kubernetes-audit objects: it converts a decoded Object (Task 1) into bounded OTEL metrics (attribute values drawn only from classify.go's Normalize*/Classify* functions, Task 2) plus one enriched log record, and converts a decoded CastHeader (Task 3) into its own session-start signal.
Processor is the single emission path for tsrecorder Kubernetes-audit objects: it converts a decoded Object (Task 1) into bounded OTEL metrics (attribute values drawn only from classify.go's Normalize*/Classify* functions, Task 2) plus one enriched log record, and converts a decoded CastHeader (Task 3) into its own session-start signal.
listenaddr
Package listenaddr classifies HTTP listener bind addresses so a receiver can tell "only this host can reach me" from "anyone who can route to me can".
Package listenaddr classifies HTTP listener bind addresses so a receiver can tell "only this host can reach me" from "anyone who can route to me can".
metricdoc
Package metricdoc is the single in-code source of truth for telemetry DOCUMENTATION metadata: each emitted metric and log event declares its name, unit, instrument, human description, and attribute keys here, and the emit sites reference those declarations so the description/unit cannot drift from what is documented.
Package metricdoc is the single in-code source of truth for telemetry DOCUMENTATION metadata: each emitted metric and log event declares its name, unit, instrument, human description, and attribute keys here, and the emit sites reference those declarations so the description/unit cannot drift from what is documented.
oas
Package oas provides a minimal stdlib-only OpenAPI 3.x spec parser with $ref resolution, bounded to the subset needed for drift detection and schema-driven fuzz testing.
Package oas provides a minimal stdlib-only OpenAPI 3.x spec parser with $ref resolution, bounded to the subset needed for drift detection and schema-driven fuzz testing.
objectstore
Package objectstore defines the provider-neutral read-only object-store contract used by durable ingestion collectors.
Package objectstore defines the provider-neutral read-only object-store contract used by durable ingestion collectors.
portservice
Package portservice maps a transport protocol and port number to the IANA service name registered for it (e.g.
Package portservice maps a transport protocol and port number to the IANA service name registered for it (e.g.
provider
Package provider abstracts the control plane (Tailscale or Headscale) behind a single ControlPlane interface plus a capability set, so the collectors and the app wiring stay provider-agnostic.
Package provider abstracts the control plane (Tailscale or Headscale) behind a single ControlPlane interface plus a capability set, so the collectors and the app wiring stay provider-agnostic.
rdns
Package rdns provides best-effort, non-blocking reverse-DNS (PTR) enrichment for external IP addresses seen in flow logs.
Package rdns provides best-effort, non-blocking reverse-DNS (PTR) enrichment for external IP addresses seen in flow logs.
redact
Package redact strips reusable credential material out of values that are about to reach a lower-trust surface — a log line, a span, the admin status page or its JSON API.
Package redact strips reusable credential material out of values that are about to reach a lower-trust surface — a log line, a span, the admin status page or its JSON API.
release
Package release provides a cached, fail-open fetcher for an external "latest version" string plus version parse/compare helpers, shared by the self update-available check (C4) and per-device version-skew metrics (B6).
Package release provides a cached, fail-open fetcher for an external "latest version" string plus version parse/compare helpers, shared by the self update-available check (C4) and per-device version-skew metrics (B6).
ringbuf
Package ringbuf provides a small, thread-safe, generic ring buffer.
Package ringbuf provides a small, thread-safe, generic ring buffer.
s3
Package s3 is a minimal read-only client for S3-compatible object storage: list a prefix, fetch an object.
Package s3 is a minimal read-only client for S3-compatible object storage: list a prefix, fetch an object.
semconv
Package semconv centralizes the OpenTelemetry attribute keys, UCUM units, and enumerated values shared across collectors and processors.
Package semconv centralizes the OpenTelemetry attribute keys, UCUM units, and enumerated values shared across collectors and processors.
stream
Package stream implements a streaming receiver that emulates a Splunk HTTP Event Collector (HEC) endpoint so Tailscale "log streaming" can push network-flow and configuration-audit logs to this collector.
Package stream implements a streaming receiver that emulates a Splunk HTTP Event Collector (HEC) endpoint so Tailscale "log streaming" can push network-flow and configuration-audit logs to this collector.
supportbundle
Package supportbundle assembles a privacy-safe support bundle: everything docs/troubleshooting.md's "Still stuck?" section previously asked an operator to gather and redact BY HAND (#321) — version, every configuration diagnostic, the full redacted effective config, component/API/export state, and the metric/log-event catalogs — as one deterministic, bounded archive.
Package supportbundle assembles a privacy-safe support bundle: everything docs/troubleshooting.md's "Still stuck?" section previously asked an operator to gather and redact BY HAND (#321) — version, every configuration diagnostic, the full redacted effective config, component/API/export state, and the metric/log-event catalogs — as one deterministic, bounded archive.
telemetry
Package telemetry is the OTEL-agnostic facade that collectors use to record metrics and emit log events.
Package telemetry is the OTEL-agnostic facade that collectors use to record metrics and emit log events.
telemetrytest
Package telemetrytest provides in-memory test helpers for asserting the OpenTelemetry output produced through the internal/telemetry Emitter.
Package telemetrytest provides in-memory test helpers for asserting the OpenTelemetry output produced through the internal/telemetry Emitter.
tsapi
Package tsapi wraps the Tailscale API: the official tsclient for snapshot resources (devices, users, DNS, ACL, settings, webhooks, contacts) plus a thin custom doer for resources the client does not cover or under-populates (key inventory, posture, log polling, and other raw-decode endpoints).
Package tsapi wraps the Tailscale API: the official tsclient for snapshot resources (devices, users, DNS, ACL, settings, webhooks, contacts) plus a thin custom doer for resources the client does not cover or under-populates (key inventory, posture, log polling, and other raw-decode endpoints).
tsapi/contract
Package contract holds the consumed-surface manifest — the authoritative list of Tailscale API GET operations that tailscale2otel decodes — and a decoder harness that exercises the real tsapi.Client methods against an httptest server.
Package contract holds the consumed-surface manifest — the authoritative list of Tailscale API GET operations that tailscale2otel decodes — and a decoder harness that exercises the real tsapi.Client methods against an httptest server.
tsapi/contract/live
Package live holds the build-tagged live Tailscale API contract test.
Package live holds the build-tagged live Tailscale API contract test.
tsscope
Package tsscope classifies Tailscale API credential scopes by privilege semantics rather than by count.
Package tsscope classifies Tailscale API credential scopes by privilege semantics rather than by count.
webhook
Package webhook implements an HTTP receiver for Tailscale webhook events.
Package webhook implements an HTTP receiver for Tailscale webhook events.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL