Transparency Logs
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
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
| Field | Description | Default | Required |
|---|---|---|---|
transparencyLogs.driver | Storage backend for the transparency log tree. Exactly one of posix, gcp, or aws must be set. More information about configuring the driver. | Yes | |
transparencyLogs.signerPrivateKey | Private key used to sign each checkpoint, as a file path or inline content. Generate one with the keygen command. | Yes | |
transparencyLogs.checkpointInterval | How 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. | 1s | No |
transparencyLogs.debug | When 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. | false | No |
transparencyLogs.witnessGroup | Witnesses 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.
| Field | Description | Default | Required |
|---|---|---|---|
driver.posix.path | Local filesystem path to store the transparency log. | Yes, with posix | |
driver.gcp.bucket | Name of the GCS bucket used to store log state. | Yes, with gcp | |
driver.gcp.bucketPrefix | Optional prefix prepended to all log resource paths, to store multiple logs in one bucket. | No | |
driver.gcp.spanner | GCP resource URI of the Spanner database instance to use. | Yes, with gcp | |
driver.aws.bucket | Name of the S3 bucket used to store log state. | Yes, with aws | |
driver.aws.bucketPrefix | Optional prefix prepended to all log resource paths, to store multiple logs in one bucket. | No | |
driver.aws.dsn | DSN of the MySQL instance to use. Carries the database password in plain text; treat it as a secret. | Yes, with aws | |
driver.aws.maxOpenConns | Maximum number of open connections to the MySQL database. | No | |
driver.aws.maxIdleConns | Maximum number of idle connections in the MySQL connection pool. | No |
- AWS
- GCP
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
hub:
transparencyLogs:
driver:
gcp:
bucket: my-transparency-log-bucket
spanner: projects/my-project/instances/my-instance/databases/transparency-logs
Configuring the witness group
| Field | Description | Default | Required |
|---|---|---|---|
witnessGroup.witnesses | List 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[].url | URL of the witness service. | Yes | |
witnessGroup.witnesses[].key | Public key of the witness, as a file path or inline content. | Yes | |
witnessGroup.threshold | Minimum number of witnesses that must cosign for the group to be satisfied. Can't exceed the number of configured witnesses. | 1 | No |
witnessGroup.timeout | Maximum time to wait for witnesses to cosign a checkpoint, as a Go duration. | 5s | No |
witnessGroup.failOpen | Publish checkpoints even when the witness policy can't be satisfied. Intended only for a non-blocking rollout of witnessing, not routine use. | false | No |
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.
| Metric | Type | Description |
|---|---|---|
tessera_appender_integrated_size | Gauge | Size of the integrated (but not necessarily published) tree. |
tessera_appender_next_index | Gauge | The next available index to be assigned to entries. |
tessera_appender_signed_size | Gauge | Size of the latest checkpoint Traefik Hub has signed. |
tessera_appender_witnessed_size | Gauge | Size of the latest checkpoint successfully cosigned by a witness. Equals signed_size when no witness is configured. |
tessera_appender_checkpoint_publication_counter_total | Counter | Number of checkpoint publication attempts, by result. |
tessera_appender_ops_duration_milliseconds | Histogram | Duration of calls to storage operations, on the driver you've configured (POSIX, GCS, or S3). |
tessera_appender_witness_requests_total | Counter | Number of attempts to get a checkpoint cosigned by the whole witness group, per publish attempt. |
tessera_appender_witness_duration_milliseconds | Histogram | Duration of a full witness-group round trip for one checkpoint publish attempt. |
tessera_witness_request_total | Counter | Number of requests sent to one individual witness's submit endpoint. |
tessera_witness_response_total | Counter | Number of responses received from one individual witness's submit endpoint. |
tessera_witness_duration_milliseconds | Histogram | Duration 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.
Related Content
- Transparency Logs for the concept and how-to guide.
