Kerberos and SSL for Trino on Kubernetes

This article shows how to enable Kerberos authentication and SSL for a Trino cluster running in Kubernetes.

The configuration scenario provided below assumes that you have deployed a clean, non-secured Trino cluster on Kubernetes as described in the Install Trino on Kubernetes article.

Prerequisites

Configurations steps

Step 1. Install Kerberos operator

Install Kerberos operator and Kerberos config using Helm as described in the Install Kerberos operator on Kubernetes article. Sample Helm values files for installing Kerberos operator and Kerberos config are below.

ko-values.yaml
replicas: 1
image:
  registry: hub.arenadata.io (1)
  repository: adc-enterprise/kerberos-operator (2)
  pullPolicy: IfNotPresent
  tag: <tag> (3)

serviceAccount:
  create: true
  automount: true

service:
  type: ClusterIP
  port: 8443

payloadNamespaces:
  names: (4)
    - kerberos-prod
    - kerberos-staging
  allowClusterRole: false (5)
  deleteProtection: true (6)
  avoidCreation: false (7)

terminationGracePeriodSeconds: 10
1 Your image storage URL.
2 Path to the Kerberos operator image repository within your storage.
3 Version of the image that Kubernetes will use.
4 List of namespaces the operator manages.
5 Explicit opt-in for cluster-wide access. When true and payloadNamespaces.names is empty, the chart creates ClusterRole/ClusterRoleBinding for access to all namespaces.
6 Add the helm.sh/resource-policy: keep annotation to payload namespaces to prevent deletion on helm uninstall.
7 Skip creating namespace resources. Use only when namespaces already exist (e.g. created by Kerberos operator).
kc-values.yaml
ldapSecret:
  enabled: true
  provider: freeipa (1)
  address: ldap://tsn-freeipa.ru-central1.internal (2)
  adminUser: uid=admin,cn=users,cn=accounts,dc=ru-central1,dc=internal (3)
  adminPassword: bigdata (4)
  baseDN: cn=services,cn=accounts,dc=ru-central1,dc=internal (5)
  ca: | <pem-certificate> (6)

kdcConfig:
  labelSelector:
    env: prod
  libdefaults:
    debug: 'false'
    default_realm: RU-CENTRAL1.INTERNAL
    dns_lookup_kdc: 'false'
    dns_lookup_realm: 'false'
    udp_preference_limit: '1'
  realm: RU-CENTRAL1.INTERNAL (7)
  domainRealm:
    ru-central1.internal: RU-CENTRAL1.INTERNAL
  realms:
    RU-CENTRAL1.INTERNAL: |
      kdc = tsn-freeipa.ru-central1.internal (8)
      admin_server = tsn-freeipa.ru-central1.internal (9)
1 Type of Kerberos provider. Can be one of the following: ad, samba, freeipa.
2 LDAP connection URL.
3 Administrator username.
4 Administrator password.
5 Search base.
6 CA certificate used to trust the LDAP server’s TLS certificate.
7 Kerberos realm.
8 Host with KDC available.
9 Host with kadmin available.

The commands for installing Helm charts:

$ helm upgrade --install kerberos-operator oci://"$PRIVATE_REGISTRY"/adc-enterprise/charts/kerberos-operator --version <chart_version> -f ko-values.yaml --namespace kerberos-operator --create-namespace
$ helm upgrade --install kerberos-config oci://"$PRIVATE_REGISTRY"/adc-enterprise/charts/kerberos-config --version <chart_version> -f kc-values.yaml --namespace kerberos-operator --create-namespace

To verify the installation, use the commands:

$ kubectl get secrets -n kerberos-operator
$ kubectl get configmaps -n kerberos-operator

Sample output:

konstantin@ka-impala-k8s-1:~/trino/trino_kerberos$ kubectl get secrets -n kerberos-operator
NAME                                      TYPE                                 DATA   AGE
kerberos-config-ldap-credentials          krb5.arenadata.io/ldap-credentials   5      7s
sh.helm.release.v1.kerberos-config.v1     helm.sh/release.v1                   1      7s
sh.helm.release.v1.kerberos-operator.v1   helm.sh/release.v1                   1      48m
konstantin@ka-impala-k8s-1:~/trino/trino_kerberos$ kubectl get configmaps -n kerberos-operator
NAME               DATA   AGE
kube-root-ca.crt   1      50m

Step 2. Create keytab and principals

  1. Create the trino-keytab.yaml manifest file with Trino principals. For example:

    apiVersion: krb5.arenadata.io/v1alpha1
    kind: Keytab
    metadata:
      name: trino-keytab
      namespace: trino
    spec:
      items:
        - realm: RU-CENTRAL1.INTERNAL (1)
          labelSelector:
            env: prod
          principals: (2)
            - HTTP/trino-cloud.ru-central1.internal
            - trino/trino-cloud.ru-central1.internal
      rotation:
        interval: 720h
        checkInterval: 1h
    1 Kerberos realm.
    2 Kerberos principals for accessing kerberized ADH services.
  2. Apply the configuration:

    $ kubectl apply -f trino-keytab.yaml
  3. Verify the keytab creation using the commands:

    $ kubectl get keytab -n trino
    $ kubectl get secret trino-keytab -n trino

    Sample output:

    NAME           ROTATION            READY             AGE    NEXTROTATION
    trino-keytab   RotationScheduled   SecretGenerated   2d6h   Next rotation required 2026-05-22T08:31:55Z
    NAME           TYPE                       DATA   AGE
    trino-keytab   krb5.arenadata.io/bundle   2      2d6h

Step 3. Update Kubernetes secrets

Your Trino installation already uses a Kubernetes secret with ADH configuration files to work with unprotected ADH services. To enable Kerberos/SSL and allow Trino to work with SSL-protected ADH services, adjust the ADH configuration files within the secret.

  1. Adjust the iceberg.properties file. The updated file should include the following properties:

    connector.name=iceberg
    hive.metastore.uri=thrift://ka-adh-2.ru-central1.internal:9083 (1)
    hive.metastore.authentication.type=KERBEROS
    hive.metastore.client.principal=trino/trino-cloud.ru-central1.internal@RU-CENTRAL1.INTERNAL (2)
    hive.metastore.client.keytab=/opt/trino-server/kerberos/keytab
    hive.metastore.service.principal=hive/_HOST@RU-CENTRAL1.INTERNAL
    hive.metastore.thrift.client.ssl.trust-certificate=/etc/ssl/truststore.jks (3)
    hive.metastore.thrift.client.ssl.trust-certificate-password=<password> (4)
    hive.metastore.thrift.impersonation.enabled=true
    fs.hadoop.enabled=True
    hive.hdfs.authentication.type=KERBEROS
    hive.hdfs.trino.principal=trino/trino-cloud.ru-central1.internal@RU-CENTRAL1.INTERNAL
    hive.hdfs.trino.keytab=/opt/trino-server/kerberos/keytab (4)
    hive.hdfs.wire-encryption.enabled=true
    hive.hdfs.impersonation.enabled=True
    hive.config.resources=/opt/trino-server/etc/catalog/core-site.xml
    hive.metastore.thrift.client.ssl.enabled=True
    1 Hive Metastore address in your ADH cluster.
    2 Kerberos principal used by Trino when connecting to Hive Metastore.
    3 The truststore to use when establishing an SSL/TLS connection to Hive Metastore.
    4 Path to the Kerberos keytab file that Trino uses to authenticate to HDFS.
  2. Adjust the core-site.xml file. The updated file should include the following properties:

    <?xml version="1.0"?>
    <configuration>
            <property>
                    <name>fs.defaultFS</name>
                    <value>hdfs://adh</value>
            </property>
            <property>
                    <name>dfs.ha.namenodes.adh</name>
                    <value>nn_ka-adh-1,nn_ka-adh-2</value>
            </property>
            <property>
                    <name>dfs.namenode.rpc-address.adh.nn_ka-adh-1</name>
                    <value>ka-adh-1.ru-central1.internal:8020</value>
            </property>
            <property>
                    <name>dfs.namenode.rpc-address.adh.nn_ka-adh-2</name>
                    <value>ka-adh-2.ru-central1.internal:8020</value>
            </property>
            <property>
                    <name>dfs.nameservices</name>
                    <value>adh</value>
            </property>
                    <property>
                    <name>dfs.client.failover.proxy.provider.adh</name>
                    <value>org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider</value>
            </property>
                    <property>
                    <name>hadoop.proxyuser.trino.groups</name>
                    <value>*</value>
            </property>
            <property>
                    <name>hadoop.proxyuser.trino.hosts</name>
                    <value>*</value>
            </property>
            <property>
                    <name>hadoop.security.authentication</name>
                    <value>kerberos</value>
            </property>
            <property>
                   <name>dfs.datanode.kerberos.principal</name>
                    <value>hdfs-datanode/_HOST@AD.RANGER-TEST</value>
            </property>
            <property>
                    <name>dfs.journalnode.kerberos.principal</name>
                    <value>hdfs-journalnode/_HOST@AD.RANGER-TEST</value>
            </property>
            <property>
                    <name>dfs.namenode.kerberos.principal</name>
                    <value>hdfs-namenode/_HOST@AD.RANGER-TEST</value>
            </property>
            <property>
                    <name>dfs.web.authentication.kerberos.principal</name>
                    <value>HTTP/_HOST@AD.RANGER-TEST</value>
            </property>
    </configuration>

    where AD.RANGER-TEST is your Kerberos realm.

  3. If you use Trino with Ranger, update the Ranger configuration according to the instruction.

  4. Re-create the Kubernetes secret:

    $ kubectl delete secret <trino-config> -n <trino-cluster-ns>
    $ kubectl -n trino create secret generic <trino-config> --from-file=core-site.xml --from-file=iceberg.properties

    where:

    • <trino-config> — name of the secret with Hadoop/Trino configs.

    • <trino-cluster-ns> — namespace used by the Trino cluster.

  5. Create a JKS truststore. This truststore should include all certificates from your ADH cluster. Create a secret for the truststore:

    $ kubectl create secret generic ca-certs --namespace <trino-cluster-ns> --from-file=truststore.jks=/etc/ssl/truststore.jks
  6. Generate a certificate for Trino:

    $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout trino-cloud.ru-central1.internal.key \
    -out trino-cloud.ru-central1.internal.crt \
    -subj "/CN=trino-cloud.ru-central1.internal"
  7. Create a secret for incoming JDBC connections:

    $ kubectl -n <trino-cluster-ns> create secret tls trino-tls-secret --cert=trino-cloud.ru-central1.internal.crt --key=trino-cloud.ru-central1.internal.key
  8. Configure your Ingress controller or load balancer to serve HTTPS using the TLS certificate stored in Kubernetes secret. For example, if Ingress is used, append the following parameters to your Ingress configuration file:

    tls:
        - hosts:
          - trino-cloud.ru-central1.internal (1)
          secretName: trino-tls-secret
    1 TLS settings for requests arriving from the given host name.

    Then, apply the updated Ingress configuration, for example:

    $ kubectl apply -f trino_ingress.yaml -n trino

Step 4. Update Trino cluster installation

  1. Modify your Trino cluster configuration file (trino_cluster_values.yaml) by adding Kerberos/SSL parameters. The updated file should look as follows:

    image:
      registry: "<registry>"
      repository: "<image>"
      tag: "<tag>"
      pullPolicy: Always
    
    useRanger: false
    configsSecretName: "trino-configs"
    
    kerberos: (1)
      realm: RU-CENTRAL1.INTERNAL
      hostname: "trino-cloud.ru-central1.internal"
      service: trino
      keytab:
        create: false
        secretName: "trino-keytab"
        labelSelector:
          env: prod
    
    worker:
      replicas: 2
      resources:
        requests:
          cpu: 500m
          memory: 1Gi
        limits:
          cpu: "2"
          memory: 4Gi
    coordinator:
      replicas: 1
      resources:
        requests:
          cpu: 500m
          memory: 1Gi
        limits:
          cpu: "2"
          memory: 4Gi
    
    ssl: (2)
      secretName: ca-certs
      trustStoreKey: truststore.jks
    1 Kerberos settings, including realm, hostname, and keytabs.
    2 Trino certificate secret name.
  2. Update your Trino cluster installation:

    $ helm upgrade --install trino-cluster oci://"$PRIVATE_REGISTRY"/adc-enterprise/charts/trino-cluster --version <version> -f trino_cluster_values.yaml --namespace <trino-cluster-ns> --create-namespace
  3. Delete old pods so that Trino operator creates new ones from an updated config:

    $ kubectl delete pods --all -n <trino-cluster-ns>
  4. When Kubernetes creates new pods, check that all the pods are in the Running state:

    $ kubectl delete pods -n <trino-cluster-ns> -l app.kubernetes.io/instance=trino-cluster

    The expected output is:

    NAME                             READY   STATUS    RESTARTS   AGE
    ad-trino-cluster-coordinator-0   1/1     Running   0          4s
    ad-trino-cluster-worker-0        1/1     Running   0          17s
    ad-trino-cluster-worker-1        1/1     Running   0          4s

Step 5. Connect to Trino via JDBC

For external JDBC access to the Trino Coordinator, you need to expose the service using one of the supported publication methods, for example, through a load balancer or Ingress controller. All configurations related to exposing a service, including DNS, annotations, Ingress settings, TLS certificates, load balancing rules, and other platform-specific settings, should be specified according to your Kubernetes environment.

  1. Get the external IP address of your load balancer or Ingress controller. For example:

    NAME            CLASS   HOSTS                              ADDRESS        PORTS     AGE
    trino-ingress   nginx   trino-cloud.ru-central1.internal   10.92.43.92   80, 443   1d7h

    Copy the external IP address (10.92.43.92 in this example) for the next steps.

  2. Connect to the Trino cluster over JDBC, for example, using DBeaver. For this, the JDBC connection string looks as follows:

    jdbc:trino://<external-ip>:443?SSL=true&SSLTrustStorePath=<path>/truststore.jks&SSLTrustStorePassword=<password>&KerberosPrincipal=user&KerberosRemoteServiceName=HTTP&KerberosKeytabPath=<path>/user.keytab

    where:

    • <external-ip> — Ingress/load balancer IP address.

    • SSLTrustStorePath=<path>/truststore.jks — path to the truststore with certificates used by DBeaver.

    • SSLTrustStorePassword=<password> — password for accessing the truststore.

    • KerberosPrincipal=user — Kerberos principal used by DBeaver for the connection.

    • KerberosRemoteServiceName=HTTP — service name used for the connection (specified in the Kubernetes keytab).

Found a mistake? Seleсt text and press Ctrl+Enter to report it