Configure web TLS for Trino on Kubernetes via CLI

In the Trino cluster configuration, the webTLS parameter group allows you to enable HTTPS on the Trino coordinator web endpoint (port 8443), while workers and internal discovery keep working over HTTP (port 8080). Unlike ssl (a client truststore/keystore, mounted both on the coordinator and worker pods), webTLS makes the coordinator a TLS server using a keystore, so the worker pods never get the private key.

webTLS is an alternative to the Ingress TLS termination, not an addition to it. The following TLS terminations are supported:

  • Ingress TLS termination (default). Ingress terminates TLS traffic and forwards to the coordinator over HTTP. The trino-cluster Ingress always targets the coordinator’s http port, so this path is unaffected by webTLS.

  • Coordinator HTTPS (webTLS). Exposes the 8443 port directly (load balancer or Ingress SSL-passthrough) and does not terminate TLS at Ingress.

Enabling both terminates TLS twice for the same request. That is only meaningful if you deliberately want re-encryption (Ingress terminates client TLS, then re-encrypts to the coordinator on 8443), which requires pointing the Ingress backend at the https port with the appropriate backend-protocol annotation.

Prerequisites

  • Trino is deployed in Kubernetes according to the instruction.

  • A PKCS12 keystore is created:

    $ openssl pkcs12 -export \
      -in <tls.crt> \
      -inkey <tls.key> \
      -out <keystore.p12> \
      -passout pass:<password>

Update the Trino cluster configuration

  1. Edit the trino-cluster.yaml configuration file by adding the webTLS configuration block:

    trino-cluster.yaml
    apiVersion: adc.arenadata.io/v1alpha1
    kind: TrinoCluster
    metadata:
      name: trino
      namespace: trino (1)
    spec:
      image: hub.arenadata.io/adc-enterprise/trino:<tag> (2)
    
      ## Image pull secret for a private registry.
      ## Set 'externalSecretName' to reference an existing Secret,
      ## or set 'credentials' and optionally 'secretName' to let the CLI create one.
      #imagePullSecret:
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-registry-secret
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-registry-secret
      #
      #  #credentials:
      #  #  registry: registry.example.com
      #  #  username: user
      #  #  password: pass
    
      hadoop: (3)
        core:
          dfs.client.failover.proxy.provider.adh: org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider
          dfs.ha.namenodes.adh: nn_tsn-adh-k8s-1,nn_tsn-adh-k8s-3
          dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:8020
          dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:8020
          dfs.nameservices: adh
          fs.defaultFS: hdfs://adh
          fs.s3a.aws.credentials.provider: org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider
          hadoop.proxyuser.trino.groups: '*'
          hadoop.proxyuser.trino.hosts: '*'
          hadoop.security.authentication: simple
        hdfs:
          dfs.client.read.shortcircuit: "false"
        hive:
          hive.metastore.sasl.enabled: "false"
          hive.metastore.uris: thrift://tsn-adh-k8s-1.ru-central1.internal:9083
          metastore.use.SSL: "false"
        ozone:
          ozone.om.address.adh.om_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:9862
          ozone.om.address.adh.om_tsn-adh-k8s-2: tsn-adh-k8s-2.ru-central1.internal:9862
          ozone.om.address.adh.om_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:9862
          ozone.om.nodes.adh: om_tsn-adh-k8s-1,om_tsn-adh-k8s-2,om_tsn-adh-k8s-3
          ozone.om.service.ids: adhom
    
      ## Kerberos configuration for authentication.
      #kerberos:
      #  realm: EXAMPLE.COM
      #
      #  # Service name in the Kerberos principal. Defaults to the product name.
      #  service: trino
      #
      #  # Hostname in the Kerberos principal.
      #  # Required for a fixed service principal; leave it empty only to derive one principal per pod from the cluster domain.
      #  hostname: kerberos.example.com
      #  keytab:
      #    # true - kerberos-operator creates the keytab Secret.
      #    # false (default) - reference an existing keytab Secret with name keytab.secretName.
      #    create: false
      #
      #    # Name of the keytab Secret.
      #    # Optional when create: true - names the generated Secret (default: <name>-keytab).
      #    # Required when create: false - must reference an existing Secret.
      #    secretName: kerberos-secret
      #
      #    # Label selector for the Pod that generates the keytab.
      #    # Required when create: true; ignored when create: false.
      #    labelSelector:
      #      env: prod
      #    #additionalPrincipals:
      #    #  - HTTP/kerberos.example.com
      #
      #    rotation:
      #      interval: 24h
      #      checkInterval: 1h
    
      ## LDAP authentication configuration.
      ## Uncomment and fill url and userBindPattern.
      ## For ldaps:// URLs the ssl: or ca: section must also be configured (depends on product)
      #ldap:
      #  # LDAP service url.
      #  url: ldaps://ldap.example.com:636
      #
      #  # LDAP user Bind pattern.
      #  userBindPattern: uid=${USER},cn=users,dc=example,dc=com
    
      ## Ranger plugin configuration.
      ## Uncomment and fill the lines below. adc apply derives the rest.
      #ranger:
      #  # fill ranger.plugin.trino.policy.rest.url below with Ranger endpoint, e.g. https://adps-adc.ru-central1.internal:6182
      #  # fill ranger.plugin.trino.service.name below with Ranger service name you want to use for product, e.g. adc_trino_id_1
      #  security:
      #    ranger.plugin.trino.policy.rest.url: ""
      #    ranger.plugin.trino.service.name: ""
      #
      #  # fill xasecure.audit.destination.solr.zookeepers below with Zookeepers endpoints to resolve solr service, e.g. adps-adc.ru-central1.internal:2181/Arenadata.Hadoop-2.solr.server
      #  audit:
      #    xasecure.audit.destination.solr.zookeepers: ""
      #
      #  # Local Ranger files 'adc apply' writes into the configs Secret.
      #  # Relative paths are resolved against the config file.
      #  files:
      #    jceksStorePath: /path/to/ranger.jceks
    
      ## Java KeyStore/TrustStore certificate configuration.
      ## Set externalSecretName to reference an existing Secret,
      ## or set files and optional secretName to have ADC create it.
      #ssl:
      #  ## Name of the Secret containing Java keystores.
      #  #secretName: custom-ssl-secret
      #  externalSecretName: existing-ssl-secret
      #
      #  # Key in the Secret containing the truststore file.
      #  trustStoreKey: truststore.jks
      #
      #  ## Password for the truststore (optional).
      #  #trustStorePassword: bigdata
      #
      #  ## Key in the Secret containing the keystore file (optional).
      #  #keyStoreKey: keystore.jks
      #
      #  ## Password for the keystore (optional).
      #  #keyStorePassword: bigdata
      #
      #  ## Alias of the key entry inside the keystore. Required by the Trino JMX exporter when scrape TLS is enabled.
      #  #keyStoreAlias: trino
      #
      #  ## Local files 'adc apply' puts into the Secret named by ssl.secretName.
      #  ## Relative paths are resolved against the config file.
      #  #files:
      #  #  trustStorePath: /path/to/truststore.jks
      #  #  #keyStorePath: /path/to/keystore.jks
    
      ## Use an external complete configs Secret instead of the one rendered by ADC.
      #configsSecret:
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-trino-configs
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-trino-configs
    
      coordinator:
        replicas: 1
        #resources:
        #  limits:
        #    cpu: 500m
        #    memory: 4Gi
        #  requests:
        #    cpu: 250m
        #    memory: 512Mi
    
        ## Component arguments. Key-value pairs passed to the component configuration.
        #args:
        #  http-server.http.port: "8080"
    
        ## Environment variables passed to the component container.
        #envs:
        #  - name: JAVA_TOOL_OPTIONS
        #    value: |-
        #      -Djavax.net.ssl.trustStore=/etc/ssl/truststore.jks
        #      -Djavax.net.ssl.trustStorePassword=bigdata
      worker:
        replicas: 1
        #resources:
        #  limits:
        #    cpu: 500m
        #    memory: 4Gi
        #  requests:
        #    cpu: 250m
        #    memory: 512Mi
    
        ## Component arguments. Key-value pairs passed to the component configuration.
        #args:
        #  http-server.http.port: "8080"
    
        ## Environment variables passed to the component container.
        #envs:
        #  - name: JAVA_TOOL_OPTIONS
        #    value: |-
        #      -Djavax.net.ssl.trustStore=/etc/ssl/truststore.jks
        #      -Djavax.net.ssl.trustStorePassword=bigdata
    
      ## Trino catalogs (one entry per .properties file).
      ## adc apply derives Kerberos/SSL fields for iceberg catalogs from the surrounding cluster config.
      catalogs: (4)
        iceberg.properties:
          connector.name: iceberg
          fs.hadoop.enabled: "true"
          hive.config.resources: /opt/trino-server/etc/catalog/core-site.xml
          hive.hdfs.impersonation.enabled: "true"
          hive.metastore.thrift.impersonation.enabled: "true"
          hive.metastore.uri: thrift://tsn-adh-k8s-1.ru-central1.internal:9083
    
      ## Monitoring configuration.
      #monitoring:
      #  # Enables Prometheus metrics export from this product's pods.
      #  exportMetrics: true
    
      ## HTTPS on the Trino coordinator web endpoint.
      ## Set externalSecretName to reference a keystore Secret,
      ## or set files and optional secretName to have ADC create it.
      webTLS: (5)
        secretName: trino-web-tls
      #  externalSecretName: existing-trino-web-tls
        keystoreKey: keystore.p12
        keystorePassword: bigdata
      #
      #  ## Local keystore 'adc apply' puts into the Secret named by webTLS.secretName.
      #  ## A relative path is resolved against the config file.
        files:
          keystorePath: ./keystore.p12
    
      ## Controls whether Secret/ConfigMap changes restart pods.
      ## Set enabled: false to update referenced Secrets without restarting
      ## the workload; pods keep running the previous configuration until
      ## the policy is re-enabled. Defaults to enabled.
      #configurationRollout:
      #  enabled: false
    1 Namespace that the Trino cluster will use.
    2 Settings for pulling the Trino cluster image.
    3 Hadoop settings that were taken from the previously created hadoop_conf.yaml.
    4 Catalog settings.
    5 Web TLS settings.
  2. Apply the configuration and deploy the Trino cluster:

    $ ./adc apply -f trino-cluster.yaml

    The expected output contains a confirmation of success:

    time="20260928084833UTC" level="info" msg="cluster trino applied to namespace trino"
  3. Verify the Trino cluster pods:

    $ kubectl get pods -n trino

    The expected output is:

    NAME                  READY   STATUS    RESTARTS   AGE
    trino-coordinator-0   1/1     Running   0          52s
    trino-worker-0        1/1     Running   0          52s

Check the JDBC connection

  1. Connect to the Trino cluster over JDBC, for example, using DBeaver. After enabling web TLS, the JDBC connection string looks as follows:

    jdbc:trino://trino-cloud.ru-central1.internal:8443?SSL=true&SSLTrustStorePath=<truststore_path>&SSLTrustStorePassword=<password>
  2. Once connected, verify the Trino cluster operability:

    SHOW CATALOGS;

    The expected output:

    Catalog   |
    ----------+
    iceberg   |
    system    |
Found a mistake? Seleсt text and press Ctrl+Enter to report it