Skip to content

Security & data handling

This page summarizes graph2otel's operational security posture — what data it handles, where that data goes, and the configuration levers available to reduce exposure. For the canonical, authoritative version (kept alongside the code, not duplicated content) plus vulnerability reporting instructions, see SECURITY.md in the repo.

Reporting a vulnerability

Report privately via GitHub's private vulnerability reporting — do not open a public issue for a security bug:

https://github.com/rknightion/graph2otel/security/advisories/new

See SECURITY.md for the full disclosure process, timelines, and scope.

Telemetry payload sensitivity

graph2otel exports identity and device management data from every tenant it's configured against. Depending on which collectors are enabled, that includes user principal names / email addresses and user object IDs; device names, serial numbers, IMEIs, and other hardware identifiers; sign-in IP addresses, geographic locations, and client application identifiers; directory/group/role membership and app credential metadata; device compliance and configuration policy state; opaque correlation/request/ incident/job/cycle/change identifiers; certificate identifiers (thumbprints, serial numbers, subject/issuer names); security alert and risk-detection details; and sign-in/ provisioning source/target identity IDs and display names.

This list is confirmed against the actual collector emission by the pre-1.0 PII & cardinality audit — see docs/pii-cardinality-audit.md — not just design intent. That audit also confirmed the boundary rule below holds in code: all of the above per-entity data is confined to the logs pipeline as structured attributes; no metric label anywhere is keyed by a user, device, or per-event identity. One deliberate protection worth calling out: the Intune audit-event stream emits the names of changed properties but never their old/new values, which can carry credentials, certificates, or PII.

All of this is exported over OTLP to the configured backend (for example Grafana Cloud). Treat the OTLP backend as a trusted data sink — anyone with read access to it can see this metadata for every configured tenant. Scope backend credentials and Graph API app registration permissions accordingly.

The cardinality boundary rule

High-cardinality, per-entity data (per-user, per-device, per-sign-in event data — UPNs, device IDs, IP addresses, correlation IDs) is never attached as an OTEL metric label. That data belongs in the logs pipeline (sign-in logs, audit logs, provisioning logs, Intune audit events) as structured log attributes, not as metric label dimensions. Metrics carry only bounded, tenant-shaped aggregates — counts by compliance state, by operating system, by policy, by risk level — never a metric series keyed by user or device identity. This is a hard modeling rule, not a tuning knob: a metric series whose cardinality grows with tenant size is a bug, not a feature request. See Signals for how this maps onto the emitted namespaces.

Levers to reduce exposure

  • Enable only the collectors you need per tenant (collectors: in Configuration) — a disabled collector makes zero Graph API calls and exports zero data for that domain.
  • Use least-privilege, read-only Graph API application permissions — never grant write scopes beyond what the Intune reports export API unavoidably requires for that one feature. Run graph2otel check to confirm your app registration's grants match what your enabled collectors actually need before your first real poll — see Getting Started.
  • Where a domain has both a snapshot/aggregate signal and a raw per-entity export, prefer the aggregate; per-entity detail should be pulled on demand, not mirrored wholesale into metric label sets.

Secrets handling

  • Auth material (client secret / client certificate path) is supplied via environment variables consumed by azidentity.DefaultAzureCredential (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, or AZURE_CLIENT_CERTIFICATE_PATH) — never as literal values in YAML. The tenants list in config only carries tenant_id / client_id and per-domain collector toggles. config.local.yaml and .env are gitignored for this reason.
  • Secrets are never logged. A code path that logs a secret or a full OAuth token is a vulnerability — report it per the process above.
  • docs/pii-cardinality-audit.md — the collector-by-collector audit that confirmed the boundary rule above holds against actual emitted telemetry.
  • docs/scale-validation.md — validation of the throttle limiters and watermark/checkpoint durability under load, the mechanisms this project's scale claims depend on.

License

graph2otel is licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only) — see LICENSE.