Skip to content

Security

Tram has no authentication or authorization of its own. Whoever can create a stream decides which ports Tram opens and where it sends data, so treat access to every configuration source like access to the Tram process:

  • API: the gRPC and HTTP APIs accept every request. They listen on localhost by default; if you bind them to other interfaces with --grpc-endpoint and --http-endpoint, restrict access, e.g. with a network policy or an authenticating proxy in front
  • Profiling: --pprof-endpoint serves the Go profiles under /debug/pprof/ on their own endpoint, without authentication; it is off by default. Profiles reveal internals such as stack traces and command-line arguments, so bind it to localhost or a port that is not exposed, and reach it with kubectl port-forward. It also turns on mutex and block profiling, which costs a little on contended locks
  • OTLP source: listens on the configured port on all network interfaces, without TLS or authentication. Anyone who can reach the port can send data into the stream. Restrict it on the network level, or terminate TLS and authenticate in a proxy in front of it
  • Sinks: an OTLP sink sends data to any URL in its spec, and insecure: true turns off certificate checks. Keep credentials in sink specs, e.g. in headers or NATS URLs, out of version control; the file sync writes new files readable only by their owner
  • Kubernetes operator: watches Stream resources in all namespaces unless --watch-namespace is set, so everyone allowed to create a Stream in a watched namespace can open ports on the Tram pod and send data anywhere Tram can reach. A Stream can also refer to secrets in its namespace, which Tram reads and passes to the stream, so its author can send their values anywhere. Grant create on streams.io.tram.core only to users you would also trust with the Tram deployment and with the secrets of that namespace. --stream-selector is no access control: anyone who can create a Stream can set the matching labels