Langfuse setup
Control Core pairs inline enforcement (Bouncer + Rego) with optional async LLM observability via self-hosted Langfuse. Langfuse is an optional deployment pick for AI engineers (traces, prompt versions, evaluations, token cost). It is not required for PBAC enforcement or compliance audit.
Grafana is also optional. Compliance evidence flows through the Control Plane audit APIs and your SIEM (Splunk, Microsoft Sentinel, Elastic, QRadar, or custom). Enable Grafana and/or Langfuse only when you want those operator or AI-engineering UIs.
Optional observability picks
| Component | Required for PBAC / audit? | Role when enabled |
|---|---|---|
| SIEM / audit outbox (default path) | Yes for compliance export | Immutable decisions → Splunk, Sentinel, Elastic, QRadar, custom |
| Grafana (optional) | No | Infrastructure metrics, Loki dashboards, shadow discovery views |
| Langfuse (optional) | No | Multi-turn LLM traces, agent graphs, evals |
Canadian sovereignty defaults (customer VPC):
TELEMETRY_ENABLED=false— no Langfuse phone-homeglobal.zeroForeignEgress=true— observability stays inside your boundary- Images and libraries are pulled online from your approved / Canadian-region registries; no foreign SaaS telemetry egress is required for core Control Core
Enable Langfuse (Helm — AWS Canada)
# Provision Secret controlcore-langfuse-secrets first (database-url, nextauth-secret, salt, encryption-key, clickhouse-url, redis-url, postgres-password).
helm upgrade --install controlcore ./controlcore \
-f values.yaml \
-f values-ca-central-1.yaml \
--set langfuse.enabled=true
Sovereignty defaults (already listed above) also pin storage classes such as gp3-encrypted-ca in ca-central-1 when you deploy on AWS Canada.
Troubleshooting: If pods stay Pending, check
nodeSelectorzoneca-central-1aand PVC storage class. Confirm Secret keys match the chart. See Troubleshooting.
Bootstrap Langfuse project (~5 min)
After Langfuse pods or Compose services are healthy, seed the default Control Core project (API keys, org, and OTLP ingest settings) with the release helper:
# From your release bundle root
bash scripts/bootstrap-langfuse-demo-project.sh
The script reads Langfuse admin credentials from your Secret or .env, creates a Control Core project if missing, and prints the OTLP endpoint and public/secret keys for Bouncer env. Re-run safely after upgrades — it is idempotent.
Troubleshooting: If the script exits non-zero, confirm Langfuse
/api/public/healthreturns 200 and that database migrations completed. For Compose labs, runbash scripts/enable-aio-langfuse.shfirst to start the Langfuse profile.
Connect the Bouncer (OTLP)
Set on each Bouncer:
CC_OTEL_ENABLED=true
CC_OTLP_ENDPOINT=langfuse.<namespace>.svc:4317 # or OTel Collector → Langfuse
Restart the Bouncer after changing env vars so the OTLP exporter picks up the endpoint.
Compose all-in-one stack:
bash scripts/enable-aio-langfuse.sh
# or
COMPOSE_PROFILES=langfuse docker compose \
-f compose.demo.yml -f compose.demo.langfuse.yml up -d
Langfuse UI (local): http://localhost:3002
Troubleshooting: If no spans appear, verify
CC_OTEL_ENABLED=true, Collector/Langfuse OTLP port 4317, and that AI traffic traversedBouncer intercept. Health:curl -fsS http://localhost:3002/api/public/health.
Air-gap telemetry posture
Self-hosted Langfuse must not phone home to foreign SaaS. Set on Langfuse worker/web and Control Plane when tracing is enabled inside a sovereign enclave:
TELEMETRY_ENABLED=false
LANGFUSE_TELEMETRY_ENABLED=false
Helm (Canadian / air-gap overlay):
global:
zeroForeignEgress: true
langfuse:
environment:
TELEMETRY_ENABLED: "false"
LANGFUSE_TELEMETRY_ENABLED: "false"
Bouncer OTLP (CC_OTLP_ENDPOINT) must target an in-cluster Langfuse or collector Service — never a public Langfuse Cloud URL in air-gap installs.
Filter traces in Langfuse
Use span attributes emitted by Control Core:
| Attribute | Meaning |
|---|---|
controlcore.decision | ALLOW, DENY, REDACT, or shadow WOULD_DENY |
controlcore.pii_detected | PII / redaction obligation applied |
controlcore.rule_matched | Rego rule id |
controlcore.spiffe_id | Workload SPIFFE ID when present |
controlcore.deployment_mode | enforce or shadow |
Shadow mode debugging
With BOUNCER_ENFORCEMENT_MODE=shadow, live traffic still pass-through while spans may tag controlcore.decision=WOULD_DENY with controlcore.rule_matched so AI developers can inspect policy impact without blocking users.
Troubleshooting: If you see
ALLOWonly in shadow, confirm a deny/redact obligation would have fired and that OTel is enabled.
Next steps
- Grafana setup — platform hub
- AI audit events — immutable SIEM events