Streaming

TLS Termination in Redpanda Console

TLS (Transport Layer Security) encrypts traffic between a client and a server. Setting up that encryption requires a certificate for the hostname the client asked for, along with the matching private key: during the TLS handshake the server presents the certificate and proves that it holds the key, and only then does either side send any HTTP.

TLS termination is the point in the network path where that handshake completes and traffic stops being encrypted. Whichever component terminates TLS is the one that:

  • Holds the certificate and the private key.

  • Clients validate when their browser shows a padlock for your hostname.

  • Must have the certificate renewed before it expires.

Everything downstream of that point receives plain HTTP, unless something re-encrypts it.

For Redpanda Console, the terminating component is either a gateway in front of Redpanda Console (a Gateway API gateway, reverse proxy, or load balancer) or the Redpanda Console process itself.

Terminating at a gateway is the preferred approach. It keeps certificate handling in one place, in front of the application, and Redpanda Console then runs with no TLS configuration at all. Terminate in Redpanda Console only when nothing in front of it can do the job.

On Kubernetes, configure TLS on a standalone Redpanda Console deployment, using either the Console resource managed by the Redpanda Operator or the Redpanda Console Helm chart.

The console stanza on a Redpanda resource is deprecated in Redpanda Operator v25.2.1 and later. When enabled, the operator generates a Console resource from the stanza and reapplies that resource on every reconciliation, overwriting your changes to it. Configure settings on a Console resource you own instead. To take ownership of a generated Console resource, see Migrate from the console stanza to a standalone Console resource.

How TLS termination works

Terminate TLS at an upstream gateway

A browser sends HTTPS traffic on port 443 to an Envoy Gateway inside the Kubernetes cluster. The Gateway terminates TLS using a certificate from the console-tls Secret and forwards plaintext HTTP on port 8080 through an HTTPRoute to the Redpanda Console Service and Pod.

The diagram shows a Gateway API gateway on Kubernetes, but the shape is the same for any reverse proxy or load balancer. A request flows like this:

  1. A browser opens a TLS connection to console.example.com on port 443. The gateway answers the handshake with the certificate it holds, so the TLS session ends at the gateway.

  2. The gateway decrypts the request, matches its hostname and path against a route, and forwards it over a separate, plaintext HTTP connection to the Redpanda Console address on port 8080.

  3. Redpanda Console receives ordinary HTTP. It has no certificate, no HTTPS listener, and no TLS configuration, so the rest of its deployment keeps its defaults.

This is the preferred approach:

  • The certificate lives on the gateway, in one place, where it can be issued and renewed automatically (by cert-manager on Kubernetes, for example). Redpanda Console never holds a certificate, and a renewal doesn’t touch Redpanda Console at all.

  • Redpanda Console keeps a single plaintext port, so nothing else about its deployment has to change. On Kubernetes, that means its Service, its route, and its health probes all keep their defaults.

  • Redpanda Console isn’t spending CPU on TLS handshakes.

  • A gateway is shared infrastructure. One certificate and one hostname policy can cover Redpanda Console alongside your other services.

Two consequences worth knowing:

  • The hop from the gateway to Redpanda Console is unencrypted. If that hop also has to be encrypted, it’s a job for the network between them (a service mesh on Kubernetes), rather than a Redpanda Console setting.

  • Redpanda Console only sends the HSTS header when its own TLS is enabled, so in this model set HSTS at the gateway instead.

Terminate TLS in Redpanda Console

A browser sends HTTPS traffic on port 443 to the Redpanda Console Service, which forwards it to port 443 on the Redpanda Console Pod. The Pod terminates TLS using a certificate mounted from the console-tls Secret, and serves a redirect on plaintext port 8080, which the kubelet probes use.

Here Redpanda Console does the work itself, and runs two servers to do it. A request flows like this:

  1. A browser opens a TLS connection on port 443. Redpanda Console answers the handshake with the certificate and key it reads from certFilepath and keyFilepath, so the TLS session ends inside the Redpanda Console process and nothing between the client and Redpanda Console ever sees plaintext.

  2. Redpanda Console’s HTTPS server, on httpsListenPort, serves the request.

  3. A second, plaintext server on listenPort accepts any HTTP request and redirects it to the HTTPS address. It builds that address from advertisedHttpsListenPort, which is separate because the port clients reach may not be the port Redpanda Console listens on.

The certificate and key arrive as files, so renewal means updating whatever supplies those files and having Redpanda Console pick them up.

Use this only when nothing in front of Redpanda Console can terminate TLS for it, such as a binary running directly on a host. On Kubernetes it also costs extra configuration, because the certificate has to be mounted into the container and the Service has to be pointed at the HTTPS listener. See what else Kubernetes needs.

Use an upstream component for TLS termination

This is the preferred way to serve Redpanda Console over TLS. When an upstream component terminates TLS, it holds the certificate, decrypts incoming requests, and forwards plaintext HTTP to Redpanda Console. Whichever component you use, it must:

  1. Terminate TLS with a certificate valid for the hostname that clients use.

  2. Route traffic to the address and plaintext port of Redpanda Console, which is 8080 by default.

  3. Pass along the original host header, so that Redpanda Console generates correct URLs from behind a proxy.

Redpanda Console needs no TLS configuration in this model. TLS is disabled by default, so usually there is nothing to change. To set it explicitly:

  • Standalone

  • Kubernetes

Add the following configuration to your /etc/redpanda/redpanda-console-config.yaml file:

server:
  listenPort: 8080
  tls:
    enabled: false

Disable TLS in the Console resource or in the Redpanda Console Helm values:

  • Operator

  • Helm

apiVersion: cluster.redpanda.com/v1alpha2
kind: Console
metadata:
  name: redpanda-console
  namespace: redpanda
spec:
  cluster:
    clusterRef:
      name: redpanda
  config:
    server:
      listenPort: 8080
      tls:
        enabled: false
config:
  server:
    listenPort: 8080
    tls:
      enabled: false

Apply with:

helm upgrade --install redpanda-console redpanda/console -f console-values.yaml

Although Redpanda Console isn’t using TLS, the traffic remains secure because the upstream component handles TLS.

If you host Redpanda Console under a sub-path of your domain, such as https://my-company.com/redpanda/console, configure HTTP path rewrites in Redpanda Console.

Terminate TLS at an Envoy Gateway

On Kubernetes, the gateway is a Gateway API Gateway. The Gateway API is the successor to the Ingress API, and the widely used ingress-nginx controller retired in March 2026, so new deployments should route through a Gateway controller. These steps use Envoy Gateway; Istio, Cilium, and NGINX Gateway Fabric work the same way, with a different gatewayClassName.

Before you start, install the Gateway API CRDs and a Gateway controller. For versions and installation steps, see Configure External Access through Gateway API.

  1. Create a Secret that holds the certificate and key for the Redpanda Console hostname, in the namespace where the Gateway runs. Use cert-manager to issue and renew it, or create it directly:

    kubectl create secret tls console-tls \
      --namespace gateway-system \
      --cert=tls.crt --key=tls.key
  2. Create a Gateway with an HTTPS listener that terminates TLS with that Secret:

    gateway.yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: my-gateway
      namespace: gateway-system
    spec:
      gatewayClassName: eg (1)
      listeners:
        - name: https
          protocol: HTTPS
          port: 443
          tls:
            mode: Terminate (2)
            certificateRefs:
              - name: console-tls
          allowedRoutes:
            namespaces:
              from: All (3)
    1 The GatewayClass name depends on your controller. Envoy Gateway installs eg.
    2 Terminate decrypts traffic at the listener and forwards it to the backend in plaintext.
    3 The listener must allow routes from the namespace where Redpanda Console runs. Use from: Selector to restrict which namespaces can attach.
  3. Apply the Gateway and confirm that the controller programmed the listener:

    kubectl apply -f gateway.yaml
    
    kubectl get gateway my-gateway --namespace gateway-system \
      -o jsonpath='{range .status.listeners[*]}{.name}: {range .conditions[*]}{.type}={.status} {end}{"\n"}{end}'

    The listener reports Accepted=True and Programmed=True.

  4. Attach Redpanda Console to the Gateway. Redpanda renders and maintains the HTTPRoute for you, pointing it at the plaintext Redpanda Console Service:

    • Operator

    • Helm

    apiVersion: cluster.redpanda.com/v1alpha2
    kind: Console
    metadata:
      name: redpanda-console
      namespace: redpanda
    spec:
      cluster:
        clusterRef:
          name: redpanda
      gateway:
        enabled: true
        parentRefs:
          - name: my-gateway
            namespace: gateway-system
            sectionName: https
        hostnames:
          - console.example.com
        path: /
        pathType: PathPrefix
    gateway:
      enabled: true
      parentRefs:
        - name: my-gateway
          namespace: gateway-system
          sectionName: https
      hostnames:
        - console.example.com
      path: /
      pathType: PathPrefix
  5. Point DNS for the hostname at the Gateway’s address, then confirm that the route attached and that the endpoint serves HTTPS:

    kubectl get httproute --namespace redpanda
    
    curl -sI https://console.example.com | head -1

The gateway block requires Redpanda Operator 26.2.1 or later, or Redpanda Console Helm chart 3.9.0 or later. Ingress and the Gateway API are mutually exclusive for Redpanda Console; enabling both fails validation. For the full reference, including how to switch between Ingress and the Gateway API, see Expose Redpanda Console with the Gateway API.

Other upstream components

Outside Kubernetes, or where no Gateway controller is available, any reverse proxy or load balancer that meets the requirements in Use an upstream component for TLS termination works, including HAProxy and cloud HTTPS load balancers. Configure TLS termination on that component and forward plaintext HTTP to the Redpanda Console address and listenPort.

Use Redpanda Console for TLS termination

When you use Redpanda Console to terminate the TLS connection, Redpanda Console starts two HTTP servers:

  • An HTTPS server on the configured HTTPS port.

  • An HTTP server on the configured HTTP port which redirects HTTP requests to the HTTPS port.

  • Standalone

  • Kubernetes

Add the following configuration to your /etc/redpanda/redpanda-console-config.yaml file:

server:
  # httpsListenPort defines the port on which Redpanda Console is listening for TLS connections, while advertisedHttpsListenPort defines the port that is advertised to clients, which may be different due to network configurations such as load balancers or proxies. advertisedHttpsListenPort is needed when redirecting a HTTP request to an HTTPS URL.
  httpsListenPort: 443
  advertisedHttpsListenPort: 443
  listenPort: 8080
  tls:
    enabled: true
    certFilepath: <path-to-cert>
    keyFilepath: <path-to-key>
    # AllowedOrigins is a list of origins that can send requests from a browser to the Redpanda Console
    # API. By default, a same-site policy is enforced to prevent CSRF-attacks.
    # Only in very specific deployment models you may need to change the secure default.
    # For example, during development, it's common to have the API server and the client running on different ports of localhost, which are treated as different origins by browsers. In this case, you would need to set `allowedOrigins` to include the origin of your client's development server.
    # allowedOrigins: []

Replace <path-to-cert> and <path-to-key> with the paths of your TLS certificate and key, respectively.

Configure TLS in the Console resource or in the Redpanda Console Helm values:

  • Operator

  • Helm

apiVersion: cluster.redpanda.com/v1alpha2
kind: Console
metadata:
  name: redpanda-console
  namespace: redpanda
spec:
  cluster:
    clusterRef:
      name: redpanda
  config:
    server:
      httpsListenPort: 443
      advertisedHttpsListenPort: 443
      listenPort: 8080
      tls:
        enabled: true
        certFilepath: /etc/console/certs/tls.crt
        keyFilepath: /etc/console/certs/tls.key
  secretMounts:
    - name: console-tls
      secretName: console-tls
      path: /etc/console/certs
  service:
    port: 443
    targetPort: 443
config:
  server:
    httpsListenPort: 443
    advertisedHttpsListenPort: 443
    listenPort: 8080
    tls:
      enabled: true
      certFilepath: /etc/console/certs/tls.crt
      keyFilepath: /etc/console/certs/tls.key
secretMounts:
  - name: console-tls
    secretName: console-tls
    path: /etc/console/certs
service:
  port: 443
  targetPort: 443

Apply with:

helm upgrade --install redpanda-console redpanda/console -f console-values.yaml

In this example, Redpanda Console is serving HTTPS traffic on port 443, where both httpsListenPort and advertisedHttpsListenPort are set to the same value. Any requests to the listenPort 8080 are redirected to the advertisedHttpsListenPort.

On Kubernetes, enabling TLS in the Redpanda Console configuration is not sufficient on its own. Redpanda Console terminates TLS inside the Pod, but by default the Service exposes only the plaintext listener, and the Ingress routes to that same Service port. The Kubernetes examples in this section therefore set three things beyond server.tls:

  • service.port and service.targetPort point the Service at the HTTPS listener. The Redpanda Console Service supports a single port, so after this change the plaintext listener is no longer reachable through the Service or the Ingress.

  • secretMounts mounts the certificate and key so that the paths in certFilepath and keyFilepath exist in the container. Create the Secret first, for example with cert-manager or kubectl create secret tls console-tls --cert=tls.crt --key=tls.key.

  • listenPort stays set. The container port that the liveness and readiness probes resolve is derived from listenPort. If you remove it, that port becomes the HTTPS port, the probes send plaintext HTTP requests to the TLS listener, and the Pod never becomes ready.

If you want Redpanda Console to serve HTTPS on a non-standard port like 8081, but you want to present the URL to users as though it’s serving on the standard HTTPS port 443, you can set httpsListenPort to 8081 and advertisedHttpsListenPort to 443. This configuration might be useful in development or testing scenarios. For example, if Redpanda Console’s internal address is https://192.168.1.100:8081 but externally it’s accessed through https://public-address.com:443, set httpsListenPort to 8081 and advertisedHttpsListenPort to 443. Despite listening internally on 8081, Redpanda Console will generate URLs for clients using port 443.

If you host Redpanda Console under a sub-path of your domain, such as https://my-company.com/redpanda/console, configure HTTP path rewrites in Redpanda Console.

HTTP Strict Transport Security (HSTS)

The HTTP Strict Transport Security (HSTS) header tells a browser to reach a domain over HTTPS only:

Strict-Transport-Security: max-age=31536000

The HSTS header instructs web browsers to:

  • Always connect to Redpanda Console using HTTPS, never HTTP

  • Automatically upgrade any HTTP requests to HTTPS for the next 365 days (31536000 seconds)

  • Refuse connections if there are certificate errors or warnings

This behavior begins after the browser’s first successful HTTPS connection to Redpanda Console.

HSTS provides protection against:

  • Protocol downgrade attacks: Prevents attackers from forcing connections to use insecure HTTP

  • Accidental insecure connections: Users typing http:// in their browser are automatically redirected to HTTPS

  • Session hijacking: Eliminates the risk window where HTTP traffic could be intercepted before redirect

Which component sends the header depends on where TLS terminates. Redpanda Console adds it automatically whenever its own TLS is enabled, so when a gateway terminates TLS instead, the gateway has to send it.

Set HSTS at an Envoy Gateway

The HTTPRoute that the Redpanda Operator and Helm chart render for you doesn’t accept route filters, so set the header on the Gateway rather than on the route. An Envoy Gateway ClientTrafficPolicy applies to every route on the Gateway it targets:

hsts.yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
  name: console-hsts
  namespace: gateway-system
spec:
  targetRef: (1)
    group: gateway.networking.k8s.io
    kind: Gateway
    name: my-gateway
  headers:
    lateResponseHeaders:
      set: (2)
        - name: Strict-Transport-Security
          value: max-age=31536000
1 The Gateway to attach the policy to. The policy must be in the same namespace as that Gateway.
2 set replaces any existing value, so the header can’t end up duplicated. This is the same value Redpanda Console sends, so moving TLS termination to the Gateway doesn’t change what browsers see.

If you write the HTTPRoute yourself instead of letting Redpanda render it, you can use the Gateway API ResponseHeaderModifier filter on the route instead. That filter is part of the Gateway API, so it works with any Gateway controller:

filters:
  - type: ResponseHeaderModifier
    responseHeaderModifier:
      set:
        - name: Strict-Transport-Security
          value: max-age=31536000

For other upstream components, set the header wherever that component configures response headers. In every case, send it only over HTTPS: a browser ignores HSTS on a plaintext response.

Verify the header

Check the response headers of a request to Redpanda Console:

curl -sIk https://<console-address>/ | grep -i strict-transport-security

Expected output:

strict-transport-security: max-age=31536000