This is documentation for the next version of Grafana Tempo documentation. For the latest stable release, go to the latest version.
Configure TLS communication
Tempo can be configured to communicate between components using Transport Layer Security, or TLS. TLS secures three categories of connections:
- Server and client: Communication between internal Tempo components (for example, querier to query-frontend).
- Receiver: Incoming trace data from instrumented applications or collectors to the distributor.
- Storage and cache: Connections to backend object storage (S3) and caches (Memcached, Redis).
Note
The ciphers and TLS version here are for example purposes only. We aren’t recommending which ciphers or TLS versions to use in production environments.
Server configuration
Every Tempo component exposes gRPC and HTTP endpoints. Use the server block to enable TLS on these endpoints.
server:
tls_cipher_suites: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
tls_min_version: VersionTLS12
grpc_tls_config:
cert_file: /tls/tls.crt
key_file: /tls/tls.key
client_auth_type: VerifyClientCertIfGiven
client_ca_file: /tls/ca.crt
http_tls_config:
cert_file: /tls/tls.crt
key_file: /tls/tls.key
client_auth_type: VerifyClientCertIfGiven
client_ca_file: /tls/ca.crtValid values for the client_auth_type are documented in the standard crypto/tls package under ClientAuthType.
Client configuration
Several Tempo components configure gRPC clients to communicate with other components. For example, the querier contacts the query-frontend to request work. If the server endpoint uses TLS, the corresponding client must also enable TLS.
Tempo uses a standard grpc_client_config stanza for each of these client connections.
You can optionally omit tls_min_version, tls_cipher_suites, and tls_insecure_skip_verify. Whether tls_server_name is required depends on your environment.
grpc_client_config:
tls_enabled: true
tls_cert_path: /tls/tls.crt
tls_key_path: /tls/tls.key
tls_ca_path: /tls/ca.crt
tls_server_name: tempo.trace.svc.cluster.local
tls_insecure_skip_verify: false
tls_cipher_suites: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
tls_min_version: VersionTLS12Set this configuration block at the following locations:
live_store_client.grpc_client_configquerier.frontend_worker.grpc_client_configbackend_scheduler_client.grpc_client_config
Additionally, memberlist must also be configured, but the client configuration is nested directly under memberlist as follows. The same configuration options are available as above.
memberlist:
tls_enabled: true
tls_cert_path: /tls/tls.crt
tls_key_path: /tls/tls.key
tls_ca_path: /tls/ca.crt
tls_server_name: tempo.trace.svc.cluster.local
tls_insecure_skip_verify: falseReceiver TLS
Receiver TLS secures the connection between trace sources, such as instrumented applications, OpenTelemetry Collectors, or Grafana Alloy, and the Tempo distributor.
The receiver configuration uses the OpenTelemetry Collector TLS settings.
For the full set of options, refer to the upstream OTLP receiver TLS documentation and the configtls package reference.
TLS fields
The following fields are available in the receiver tls block:
Configure server-only TLS
For server-only TLS, the distributor presents its certificate and clients verify it.
Only cert_file and key_file are required:
distributor:
receivers:
otlp:
protocols:
grpc:
tls:
cert_file: /tls/tls.crt
key_file: /tls/tls.key
min_version: "1.2"Configure mutual TLS (mTLS)
For mutual TLS, both the server and client present certificates.
Add client_ca_file so the distributor requires and verifies client certificates:
distributor:
receivers:
otlp:
protocols:
grpc:
tls:
cert_file: /tls/tls.crt
key_file: /tls/tls.key
client_ca_file: /tls/ca.crt
min_version: "1.2"Supported receiver TLS paths
You can set a tls block on the following receiver configurations:
distributor.receivers.otlp.protocols.grpc.tlsdistributor.receivers.otlp.protocols.http.tlsdistributor.receivers.kafka.tls(client TLS for connecting to Kafka brokers)distributor.receivers.zipkin.tlsdistributor.receivers.jaeger.protocols.grpc.tlsdistributor.receivers.jaeger.protocols.thrift_http.tls
Note
The Kafka receiver TLS block configures client TLS for the connection to Kafka brokers, unlike the other receiver TLS blocks which configure server TLS for incoming connections.
Configure the sending side
When you enable TLS on the Tempo receiver, you must also configure TLS on the client that sends traces. The following example shows a matching Grafana Alloy configuration for an OTLP gRPC exporter with server-only TLS:
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo.trace.svc.cluster.local:4317"
tls {
ca_file = "/tls/ca.crt"
}
}
}For mTLS, include the client certificate and key:
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo.trace.svc.cluster.local:4317"
tls {
ca_file = "/tls/ca.crt"
cert_file = "/tls/tls.crt"
key_file = "/tls/tls.key"
}
}
}Storage and cache TLS
S3 and S3-compatible storage
If you use a self-managed S3-compatible backend (for example, MinIO) with a custom CA or client certificates, configure TLS on the S3 storage backend.
The TLS fields are set inline under storage.trace.s3:
storage:
trace:
backend: s3
s3:
bucket: tempo-traces
endpoint: minio.example.com:9000
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_key_path: /tls/tls.key
tls_server_name: minio.example.com
tls_insecure_skip_verify: false
tls_min_version: VersionTLS12GCS and Azure Blob Storage rely on their respective SDK defaults for TLS and don’t expose separate TLS fields in the Tempo configuration.
Redis cache
If you use Redis as a cache backend, enable TLS with the tls_enabled field.
Redis TLS has limited configuration. It supports tls_enabled and tls_insecure_skip_verify but doesn’t expose CA or client certificate path fields:
cache:
caches:
- redis:
endpoint: redis.example.com:6380
tls_enabled: true
tls_insecure_skip_verify: false
roles:
- parquet-footer
- bloom
- frontend-searchGateway and ingress TLS
Tempo doesn’t include a built-in gateway component. If you end TLS at an ingress controller, load balancer, or reverse proxy in front of Tempo, configure TLS on that component rather than in the Tempo configuration. When TLS is ended at the ingress, Tempo receivers don’t need TLS configured for internal connections.
Configure TLS with Helm
To configure TLS with the Helm chart, you must have a TLS key-pair and CA certificate stored in a Kubernetes secret.
The following example mounts a secret called tempo-distributed-tls into the pods at /tls and modifies the configuration of Tempo to use the files.
In this example, the Tempo components share a single TLS certificate.
The tls_server_name configuration must match the certificate.
distributor:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
blockBuilder:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
liveStore:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
backendScheduler:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
backendWorker:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
memcached:
extraArgs:
- -Z
- -o
- ssl_chain_cert=/tls/tls.crt,ssl_key=/tls/tls.key
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
metricsGenerator:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
querier:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
queryFrontend:
extraVolumeMounts:
- mountPath: /tls
name: tempo-distributed-tls
extraVolumes:
- name: tempo-distributed-tls
secret:
secretName: tempo-distributed-tls
tempo:
readinessProbe:
httpGet:
scheme: HTTPS
structuredConfig:
memberlist:
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_enabled: true
tls_key_path: /tls/tls.key
tls_server_name: tempo-distributed.trace.svc.cluster.local
distributor:
receivers:
otlp:
protocols:
grpc:
tls:
ca_file: /tls/ca.crt
cert_file: /tls/tls.crt
key_file: /tls/tls.key
live_store_client:
grpc_client_config:
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_enabled: true
tls_key_path: /tls/tls.key
tls_server_name: tempo-distributed.trace.svc.cluster.local
backend_scheduler_client:
grpc_client_config:
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_enabled: true
tls_key_path: /tls/tls.key
tls_server_name: tempo-distributed.trace.svc.cluster.local
cache:
caches:
- memcached:
consistent_hash: true
host: tempo-distributed-memcached
service: memcached-client
timeout: 500ms
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_enabled: true
tls_key_path: /tls/tls.key
tls_server_name: tempo-distributed.trace.svc.cluster.local
roles:
- parquet-footer
- bloom
- frontend-search
querier:
frontend_worker:
grpc_client_config:
tls_ca_path: /tls/ca.crt
tls_cert_path: /tls/tls.crt
tls_enabled: true
tls_key_path: /tls/tls.key
tls_server_name: tempo-distributed.trace.svc.cluster.local
server:
grpc_tls_config:
cert_file: /tls/tls.crt
client_auth_type: VerifyClientCertIfGiven
client_ca_file: /tls/ca.crt
key_file: /tls/tls.key
http_tls_config:
cert_file: /tls/tls.crt
client_auth_type: VerifyClientCertIfGiven
client_ca_file: /tls/ca.crt
key_file: /tls/tls.key
traces:
otlp:
grpc:
enabled: trueRefer to the
prometheus.scrape docs for Alloy to configure TLS on the scrape.
A relabel configuration like the following does this configuration for you dynamically.
{
source_labels: ['__meta_kubernetes_pod_annotation_prometheus_io_scheme'],
action: 'replace',
target_label: '__scheme__',
regex: '(https?)',
replacement: '$1',
},
