Skip to main content

Transparency Logs

Early Access

Transparency logs are currently in early access, available starting v3.21.0-ea.3.

See Transparency Logs for the concept and a step-by-step guide to enabling this feature. This page lists every configuration field.

Configuration Example

values.yaml
hub:
transparencyLogs:
driver:
posix:
path: /data/transparency-logs
signerPrivateKey: /etc/traefik-hub/transparency-logs/private.key
checkpointInterval: 10s
debug: false
witnessGroup:
threshold: 1
witnesses:
- url: https://witness.example.com
key: /etc/traefik-hub/transparency-logs/witness-public.key

Configuration Options

FieldDescriptionDefaultRequired
transparencyLogs.driverStorage backend for the transparency log tree. Exactly one of posix, gcp, or aws must be set. More information about configuring the driver.Yes
transparencyLogs.signerPrivateKeyPrivate key used to sign each checkpoint, as a file path or inline content. Generate one with the keygen command.Yes
transparencyLogs.checkpointIntervalHow often a new checkpoint is signed, as a Go duration (for example 10s; include the unit of time). Tessera enforces a minimum per storage driver, or Traefik Hub refuses to start: 100ms for posix, 1s for aws, 1.2s for gcp.1sNo
transparencyLogs.debugWhen true, also stores the full rendered log line in the transparency log, not only its hash. Turn off before production: it duplicates your log content.falseNo
transparencyLogs.witnessGroupWitnesses that must cosign each checkpoint before Traefik Hub considers it committed. More information about configuring the witness group.No

Configuring the driver

Exactly one of the following must be set under transparencyLogs.driver:

The gcp driver authenticates with the default Google Cloud credential chain: environment variables (GOOGLE_APPLICATION_CREDENTIALS pointing to a mounted service account key), or GKE Workload Identity. The aws driver authenticates with the default AWS credential chain: environment variables (for example AWS_ACCESS_KEY_ID), IRSA, or the instance profile. Neither accepts static credentials as a config field directly, so grant the gateway's service account access to the bucket (and Spanner database, or MySQL instance) through your cloud provider instead.

FieldDescriptionDefaultRequired
driver.posix.pathLocal filesystem path to store the transparency log.Yes, with posix
driver.gcp.bucketName of the GCS bucket used to store log state.Yes, with gcp
driver.gcp.bucketPrefixOptional prefix prepended to all log resource paths, to store multiple logs in one bucket.No
driver.gcp.spannerGCP resource URI of the Spanner database instance to use.Yes, with gcp
driver.aws.bucketName of the S3 bucket used to store log state.Yes, with aws
driver.aws.bucketPrefixOptional prefix prepended to all log resource paths, to store multiple logs in one bucket.No
driver.aws.dsnDSN of the MySQL instance to use. Carries the database password in plain text; treat it as a secret.Yes, with aws
driver.aws.maxOpenConnsMaximum number of open connections to the MySQL database.No
driver.aws.maxIdleConnsMaximum number of idle connections in the MySQL connection pool.No
values.yaml
hub:
transparencyLogs:
driver:
aws:
bucket: my-transparency-log-bucket
dsn: user:password@tcp(my-db-instance.cluster.us-east-1.rds.amazonaws.com:3306)/transparency_logs

Configuring the witness group

FieldDescriptionDefaultRequired
witnessGroup.witnessesList of witnesses to cosign each checkpoint. You must list at least one when witnessGroup is set; Traefik Hub refuses to start otherwise.Yes, if witnessGroup is set
witnessGroup.witnesses[].urlURL of the witness service.Yes
witnessGroup.witnesses[].keyPublic key of the witness, as a file path or inline content.Yes
witnessGroup.thresholdMinimum number of witnesses that must cosign for the group to be satisfied. Can't exceed the number of configured witnesses.1No
witnessGroup.timeoutMaximum time to wait for witnesses to cosign a checkpoint, as a Go duration.5sNo
witnessGroup.failOpenPublish checkpoints even when the witness policy can't be satisfied. Intended only for a non-blocking rollout of witnessing, not routine use.falseNo

failOpen doesn't weaken witnessing, it removes it for that checkpoint. With it unset and a witness down, Traefik Hub publishes nothing, so the log stays behind instead of advancing unverified. With failOpen: true, the same checkpoint publishes carrying only your own signature, so the log keeps moving, but a witness outage becomes invisible instead of blocking. Use failOpen: true only while first rolling out a witness, to confirm it's reachable and correctly configured without blocking checkpoint publication in the meantime. Turn it off once witnessing is in steady use, since leaving it on defeats the guarantee a witness exists to provide.

Generating keys

Traefik Hub ships a keygen command for generating the log's own signing key:

traefik-hub keygen --name <name> --outputDir <dir> [--force]

This writes private.key (mode 0600) and public.key (mode 0644) to <dir>. --name becomes part of the key's identity: Tessera writes it as the checkpoint's origin, so anyone verifying the log later needs this exact value. Use a schema-less URL for it, such as example.com/my-log. It doesn't need to resolve to anything, but a plain name risks colliding with another log's origin, since nothing enforces uniqueness otherwise. Use private.key for transparencyLogs.signerPrivateKey. Share public.key with your witness, so it can verify checkpoints came from you, and with anyone who needs to independently verify the log later.

Don't use keygen to generate a witness's own keypair. It only produces plain Ed25519 keys, and some verification tooling only recognizes the cosignature format a witness key needs. Generate a witness's keypair with its own tooling instead, for example transparency-dev/witness's generate_keys command, which produces the correct format.

Metrics

To see these metrics, enable transparency logs and configure metrics.otlp. Tessera, the library behind transparency logs, instruments through the global OpenTelemetry meter provider, which metrics.otlp sets up and metrics.prometheus does not, so enabling Prometheus alone won't expose these metrics. Counters and histograms are renamed on Prometheus ingest: a counter gains a _total suffix, and a histogram expands into _bucket, _count, and _sum series with its unit appended to the name. Gauges are unaffected. The table below gives each name as Prometheus exposes it.

MetricTypeDescription
tessera_appender_integrated_sizeGaugeSize of the integrated (but not necessarily published) tree.
tessera_appender_next_indexGaugeThe next available index to be assigned to entries.
tessera_appender_signed_sizeGaugeSize of the latest checkpoint Traefik Hub has signed.
tessera_appender_witnessed_sizeGaugeSize of the latest checkpoint successfully cosigned by a witness. Equals signed_size when no witness is configured.
tessera_appender_checkpoint_publication_counter_totalCounterNumber of checkpoint publication attempts, by result.
tessera_appender_ops_duration_millisecondsHistogramDuration of calls to storage operations, on the driver you've configured (POSIX, GCS, or S3).
tessera_appender_witness_requests_totalCounterNumber of attempts to get a checkpoint cosigned by the whole witness group, per publish attempt.
tessera_appender_witness_duration_millisecondsHistogramDuration of a full witness-group round trip for one checkpoint publish attempt.
tessera_witness_request_totalCounterNumber of requests sent to one individual witness's submit endpoint.
tessera_witness_response_totalCounterNumber of responses received from one individual witness's submit endpoint.
tessera_witness_duration_millisecondsHistogramDuration of a call to one individual witness's submit endpoint.

The tessera_appender_witness_* metrics summarize one checkpoint-publish attempt as a whole. The tessera_witness_* metrics (no appender_ prefix) break that down per individual witness, which is useful once you have more than one configured.

signed_size is recorded the moment Traefik Hub signs a new checkpoint, before contacting any witness. witnessed_size only advances once a witness has successfully cosigned that checkpoint. If a witness call fails, the checkpoint isn't published and witnessed_size doesn't move for that attempt, even though signed_size already did.

Set up an alert that compares the two metrics directly: if tessera_appender_signed_size keeps advancing while tessera_appender_witnessed_size stays behind, your checkpoints are being signed but not cosigned. This tells you the log is unprotected right now, which an error counter alone can't show once the underlying issue has passed. You can set this up with whatever tool consumes your metrics.otlp data, such as Datadog or Grafana. If you use Prometheus, enable metrics.otlp alongside it and route that data through an OpenTelemetry Collector (or Prometheus's own OTLP ingestion, if available). These metrics don't reach Prometheus through metrics.prometheus alone.