Skip to content

Observability ​

Scope: namespaced · Kind: Observability (short name obs, plural observabilities) · Group: core.navique.com/v1alpha1

LLM observability — traces, evals, prompt management. Observability is the generic observability workload: spec.type selects the backend implementation. Today only langfuse is implemented (Langfuse v3 via the langfuse-operator); other types are scaffolded for the future.

Spec ​

FieldTypeDescription
typeenum (required)Backend implementation. Only langfuse is implemented today
secretsRefLocalRef (optional)Same-namespace SecretsManagement to wait for. Leave it out to use plain Kubernetes Secrets you manage yourself — see secretsRef
meshobjectOpt the namespace into the cluster ServiceMesh (auto / enabled / disabled)
imageobjectImage override for the selected backend
ingressobjectHost + TLS (TLS ⇒ ensures cert-manager)
ssoobjectOIDC/SSO login (see SSO)
langfuseobjectLangfuse-specific configuration — present when type: langfuse (see langfuse block)

These top-level fields are common to every backend type. Backend-specific configuration lives under a block named after the type (spec.langfuse for the Langfuse backend).

type ​

typeStatusEmits
langfuseImplementedA LangfuseInstance (langfuse.palena.ai/v1alpha1) via the langfuse-operator

Other backend types are reserved and not yet implemented; setting one yields a clear "not yet implemented" status condition.

langfuse block ​

When type: langfuse, spec.langfuse holds the Langfuse v3 wiring. Langfuse v3 needs Postgres, ClickHouse, Redis, and object (blob) storage; each datastore can reference a datastore resource or point at an external host.

FieldTypeDescription
postgresDatastoreRef (required)Reference a PostgresCluster or external
clickhouseDatastoreRef (required)Reference a ClickHouseCluster or external
redisDatastoreRef (required)Reference a RedisInstance or external
blobobject (required)Object storage (required by Langfuse v3): S3 / Azure / GCS
authobjectnextAuthUrl; secret/salt auto-generated by the operator
bootstrapobjectHeadless seed of an org / project / API key + admin user (see Bootstrap)
licenseSecretRefSecretKeyRefLangfuse Enterprise licence — per-person access (see Giving people access)
defaultAccessobjectAutomatic access for everyone who signs in (see Giving people access)

DatastoreRef ​

FieldDescription
moderef (a datastore resource) or external
refThe datastore resource to use (mode ref)
databaseNameDatabase inside the shared datastore. Postgres: required for a managed/adopted PostgresCluster. ClickHouse: optional (default default); must be listed in the ClickHouseCluster’s spec.databases (a Stack does this) — Langfuse waits for it. Letters, digits and _ only
connectionSecretRefConnection Secret (mode external)

blob (discriminated union) ​

provider selects the backend; supply the matching block. Credentials are read from a Secret in the namespace under canonical keys; omitting the credentials secret selects ambient cloud credentials (IRSA / Workload Identity).

ProviderBlockCredential keys
s3 (default)s3 (bucket, region, endpoint, forcePathStyle)access-key-id, secret-access-key
azureazure (storageAccountName, containerName, endpoint)account-key
gcsgcs (bucket, projectId)credentials (SA JSON)

What it emits ​

For type: langfuse, the controller resolves the datastores, ensures cert-manager if TLS/ingress is enabled, ensures the langfuse-operator, and emits a LangfuseInstance (langfuse.palena.ai/v1alpha1) referencing the resolved datastores and secrets. The managed/adopt/external provenance lives in the referenced datastore resources — Observability just points at them.

Operator-managed datastores by default

For ClickHouse and Redis, the langfuse-operator can manage them internally. Unless you reference an external datastore, the controller defaults to operator-managed ClickHouse/Redis — so you don't strictly need a dedicated ClickHouseCluster / RedisInstance. Postgres is typically shared with the Gateway.

Example ​

yaml
apiVersion: core.navique.com/v1alpha1
kind: Observability
metadata:
  name: observability
  namespace: forge-langfuse
spec:
  type: langfuse
  secretsRef: { name: langfuse-secrets }
  ingress: { enabled: true, host: langfuse.forge.example.com, tls: true }
  langfuse:
    postgres:   { mode: ref, ref: { name: forge-pg, namespace: forge-data }, databaseName: langfuse }
    clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
    redis:      { mode: ref, ref: { name: forge-redis, namespace: forge-data } }
    blob:
      provider: azure
      azure:
        storageAccountName: forgelangfuse
        containerName: langfuse-events

SSO / OIDC login ​

spec.sso enables single sign-on. For the Langfuse backend it uses Langfuse v3's generic custom-OIDC provider: the operator sets the LangfuseInstance's native spec.auth.oidc block, which the langfuse-operator translates to Langfuse's AUTH_CUSTOM_* configuration. The OAuth client credentials come from a same-namespace Secret (via SecretsManagement).

FieldDescription
issuerURLOIDC issuer / discovery base URL
clientSecretRef.nameSecret holding the OAuth client (keys default to client-id / client-secret)
scopesRequested scopes (default openid, email, profile)
providerNameLogin-button label (AUTH_CUSTOM_NAME)

The provider, tenantID, and explicit-endpoint fields of the shared SSO type are Gateway-only and ignored here.

The IdP must whitelist the custom-OIDC callback <publicURL>/api/auth/callback/custom, so enable spec.ingress (or set langfuse.auth.nextAuthUrl) to a public URL.

yaml
spec:
  type: langfuse
  sso:
    issuerURL: https://idp.example.com
    providerName: "Acme SSO"
    clientSecretRef: { name: langfuse-oidc }

TIP

Static OIDC providers are part of Langfuse's open-source self-hosted build. Only the in-UI SSO setup, per-org SSO enforcement, and RBAC/SCIM are Langfuse Enterprise features.

Bootstrap ​

spec.langfuse.bootstrap headlessly seeds an organization, a project, an initial API key, and an admin user into a fresh community Langfuse via the LANGFUSE_INIT_* environment. This lets the platform come up fully wired without anyone logging into the Langfuse UI first — for example so a Gateway can export traces against a known project key on a community Langfuse that cannot otherwise mint project keys.

FieldDescription
organizationInitial organization name
projectInitial project name
apiKeySecretRefSecret to populate with the seeded project's public/secret key
adminAdmin user (email + password from a Secret) seeded on first start

The seeded credentials are written through to owned Secrets so consumers (Gateway trace export, the management console) can read them without UI steps.

Giving people access ​

Langfuse has two ways in, and they need different things:

  • One by one — an Identity of type: observability (with observabilityRef and a role: viewer, member, admin or owner) makes that person a member of this Langfuse's organization: the bootstrap organization when bootstrap is on, which holds the projects and traces. Langfuse's member management is an Enterprise feature, so this needs licenseSecretRef (the Langfuse Enterprise licence key). Without it, such an Identity reports that it needs the licence.
  • Everyone who signs in — defaultAccess adds every new Langfuse user (for example on first company sign-in) to the bootstrap organization and project automatically. No licence is needed. Without one, orgRole is the role that counts on every project: project-level roles (projectRole) are also an Enterprise feature.

status.peopleAccess reports whether one-by-one access is Available, or why not (NeedsLicense, NeedsNewerLangfuseOperator), and status.signInAccessRole the role automatic access actually grants. The management console reads both to offer the right option.

FieldDescription
licenseSecretRefSecret holding the Langfuse Enterprise licence (key license by default)
defaultAccess.orgRoleOWNER / ADMIN / MEMBER / VIEWER (default) / NONE
defaultAccess.projectRoleOWNER / ADMIN / MEMBER / VIEWER (default) — Enterprise only

Requires bootstrap for defaultAccess (refused at admission otherwise).

Secrets ​

nextauth-secret and salt are auto-generated and rotated by the langfuse-operator into a <instance>-generated-secrets Secret — you do not source these from Key Vault unless you want to override them. Datastore credentials come from the referenced datastore resources' materialized Secrets (plus Key Vault for external datastores). See Secrets Management.

Status ​

Per-datastore readiness, instance readiness, and the ingress host, plus the standard conditions and observedGeneration. An unimplemented type surfaces a clear "not yet implemented" condition.

Open core under AGPL-3.0. Enterprise components are proprietary and license-gated.