Security

This page covers authentication and authorization.

Authentication

Trino supports several authentication types.

Different authentication types can be used simultaneously.

Password

The Trino operator currently supports the following PASSWORD authenticators.

File

The file based authentication can be defined as follows. First create a secret with your users:

apiVersion: v1
kind: Secret
metadata:
  name: trino-users
type: kubernetes.io/opaque
stringData:
  admin: admin
  alice: alice
  bob: bob

This contains username and password pairs as shown in the previous snippet. The username and password combinations are provided in the stringData field.

The Secret is referenced in an AuthenticationClass.

apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: simple-trino-users
spec:
  provider:
    static:
      userCredentialsSecret:
        name: trino-users

Then reference the AuthenticationClass in your TrinoCluster definition:

apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: simple-trino
spec:
  clusterConfig:
    authentication:
      - authenticationClass: simple-trino-users
      - authenticationClass: ...

Multiple authentication classes with different user secrets can be provided.

The operator never reads secrets directly, but mounts them directly into the Pod. Volume mount names can not exceed 63 characters due to Kubernetes restrictions.

For uniqueness, the volume mount name is internally build up of the name of the AuthenticationClass. This means the AuthenticationClass name must not exceed 63 characters.

Due to Kubernetes restrictions, the name of the AuthenticationClass must not exceed 63 characters.

Changes to the referenced user Secret (e.g. adding or removing a user) are updated in Trino without restarts but after a small delay. This heavily depends on Kubernetes and may take a couple of minutes.

Adding or removing an AuthenticationClass will however result in a Pod restart.

LDAP

The Trino operator supports LDAP authentication as well and authentication in Stackable is done using AuthenticationClasses:

apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: my-ldap
spec:
  provider:
    ldap:
      hostname: openldap.default.svc.cluster.local
      searchBase: ou=users,dc=example,dc=org
...
You can follow the Authentication with OpenLDAP tutorial to learn how to create an AuthenticationClass for an LDAP server.

With an AuthenticationClass ready, PASSWORD authentication using LDAP is done by referencing the LDAP AuthenticationClass:

apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: trino-with-ldap
spec:
  clusterConfig:
    authentication:
      - authenticationClass: my-ldap

In the Trino CLI and web interface, LDAP users can now be used to log in.

OAUTH2

For using OAuth 2.0 authentication, TLS must be enabled and a Secret with the client credentials must be created:

apiVersion: v1
kind: Secret
metadata:
  name: oidc-secret
type: kubernetes.io/opaque
stringData:
  clientId: trino
  clientSecret: trino-client-secret

In the AuthenticationClass, an OpenID Connect (OIDC) provider can be specified:

apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: oidc
spec:
  provider:
    oidc:
      hostname: keycloak.default.svc.cluster.local
      port: 8080
      rootPath: /realms/stackable
      scopes:
      - openid
      principalClaim: preferred_username
...
There is no generic support for OAuth 2, only OpenID Connect providers are supported.

The AuthenticationClass and the Secret with the client credentials must be referenced in the authentication section of the Trino cluster:

apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: trino-with-ldap
spec:
  clusterConfig:
    authentication:
    - authenticationClass: oidc
      oidc:
        clientCredentialsSecret: oidc-secret
    tls:
      serverSecretClass: tls
...

Authorization

In order to authorize Trino via OPA, a ConfigMap containing a rego rule package for Trino has to be applied and referenced in the TrinoCluster resource. The following example is an all-access Rego rule for testing with the user admin. Do not use it in production! The rego rules below are written using Rego V1 to be compatible with the OPA v1.0.0 release.

For a production setup you will use something much more granular. We provide a detailed set of rego rules in our integration tests. Details can be found below in the fine-granular rego rule section.
Due to changes in the Trino OPA authorizer, rego rules differ between version 414 and newer versions.
  • 414

  • Newer than 414

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: opa-bundle-trino
  labels:
    opa.stackable.tech/bundle: "true"
data:
  trino.rego: |
    package trino

    import rego.v1

    default allow = false

    allow if {
      is_admin
    }

    is_admin() if {
      input.context.identity.user == "admin"
    }
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: opa-bundle-trino
  labels:
    opa.stackable.tech/bundle: "true"
data:
  trino.rego: |
    package trino

    import rego.v1

    default allow = false

    # Allow non-batched access
    allow if {
      is_admin
    }

    # Allow batched access
    batch contains i if {
      some i
      input.action.filterResources[i]
      is_admin
    }

    # Corner case: filtering columns is done with a single table item, and many columns inside
    batch contains i if {
      some i
      input.action.operation == "FilterColumns"
      count(input.action.filterResources) == 1
      input.action.filterResources[0].table.columns[i]
      is_admin
    }

    # Filter rows according to an expression
    rowFilters contains row_filter if {
      input.action.operation == "GetRowFilters"

      input.action.resource.table.catalogName == "default"
      input.action.resource.table.schemaName == "hr"
      input.action.resource.table.tableName == "employee"

      row_filter := {
        "expression": "user = current_user",
        "identity": "system_user",
      }
    }

    # Mask columns according to an expression
    columnMask := column_mask if {
      input.action.operation == "GetColumnMask"

      input.action.resource.column.catalogName == "default"
      input.action.resource.column.schemaName == "default"
      input.action.resource.column.tableName == "cards"
      input.action.resource.column.columnName == "SSN"

      column_mask := {
        "expression": "'XXX-XX-' + substring(credit_card, -4)",
        "identity": "system_user",
      }
    }

    is_admin() if {
      input.context.identity.user == "admin"
    }

Reference the package in the Trino cluster:

...
spec:
  clusterConfig:
    authorization:
      opa:
        configMapName: opa  (1)
        package: trino      (2)
...
1 The name of the OpaCluster
2 The name of the package defined in the rego rule ConfigMap

Fine-granular rego rules

The operator repository contains a more production-ready set of rego-rules in this integration test. The test uses the following:

  • a set of rules provided by the Stackable Data Platform, together with associated test files that can be used directly with OPA (i.e. outside the integration test context)

    • these files can be tested by using the built-in policy test functionality and running opa test <path-to-trino-rule-folder> -b

  • a sample set of trino policies that represents what is to be provided by the user.

The rules implement system-level access control files (catalog-level access control is currently not provided). As illustrated by the integration test, both internal and customer-provided policies are deployed as ConfigMaps and there is thus no requirement for an extra configuration file in JSON to be created.

Please note these additional points:

  • Roles are not checked, only users and groups.

  • Principal rules are deprecated and not implemented.

  • The allow property of the catalog rules accepts only the new values all, read-only, and none, but not the legacy values true and false.

  • The Rego rules attempt to implement the Java implementation as close as possible although this is not always reflected clearly in the documentation (for instance the documentation states that "If neither impersonation nor principal rules are defined, impersonation is not allowed", although in practice users are always allowed to impersonate themselves).

Define a secure cluster

For secure connections the following steps must be taken:

  1. Enable authentication

  2. Enable TLS between the clients and coordinator

  3. Enable internal TLS for communication between coordinators and workers

Via authentication

If authentication is enabled, TLS for the coordinator as well as a shared secret for internal communications (this is base64 and not encrypted) must be configured.

Securing the Trino cluster will disable all HTTP ports and disable the web interface on the HTTP port as well. In the definition below the authentication is directed to use the trino-users secret and TLS communication will use a certificate signed by the Secret Operator (indicated by autoTls).

---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCatalog
metadata:
  name: hive
  labels:
    trino: simple-trino
spec:
  connector:
    hive:
      metastore:
        configMap: simple-hive-derby
---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: simple-trino
spec:
  image:
    productVersion: "451"
  clusterConfig:
    tls:
      serverSecretClass: trino-tls (1)
    authentication:
      - authenticationClass: trino-users (3)
    catalogLabelSelector:
      matchLabels:
        trino: simple-trino (5)
  coordinators:
    roleGroups:
      default:
        replicas: 1
  workers:
    roleGroups:
      default:
        replicas: 1
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
  name: trino-tls (1)
spec:
  backend:
    autoTls: (6)
      ca:
        secret:
          name: secret-provisioner-trino-tls-ca (2)
          namespace: default
        autoGenerate: true
---
apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: trino-users (3)
spec:
  provider:
    static:
      userCredentialsSecret:
        name: trino-users (4)
---
apiVersion: v1
kind: Secret
metadata:
  name: trino-users (4)
type: kubernetes.io/opaque
stringData:
  admin: admin
---
apiVersion: hive.stackable.tech/v1alpha1
kind: HiveCluster
metadata:
  name: simple-hive-derby
spec:
  image:
    productVersion: 3.1.3
  clusterConfig:
    database:
      connString: jdbc:derby:;databaseName=/tmp/metastore_db;create=true
      user: APP
      password: mine
      dbType: derby
  metastore:
    roleGroups:
      default:
        replicas: 1
1 The name of (and reference to) the SecretClass
2 The name of (and reference to) the Secret
3 The AuthenticationClass for file based user control
4 The Secret containing user and password combinations in plaintext
5 TrinoCatalog reference
6 TLS mechanism

The CLI now requires that a path to the keystore and a password be provided:

./trino.jar --debug --server https://172.18.0.3:31748
--user=admin --keystore-path=<path-to-keystore.p12> --keystore-password=<password>

Via TLS only

This will disable the HTTP port and UI access and encrypt client-server communications.

---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCatalog
metadata:
  name: hive
  labels:
    trino: simple-trino
spec:
  connector:
    hive:
      metastore:
        configMap: simple-hive-derby
---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: simple-trino
spec:
  image:
    productVersion: "451"
  clusterConfig:
    tls:
      serverSecretClass: trino-tls (1)
    catalogLabelSelector:
      matchLabels:
        trino: simple-trino (2)
  coordinators:
    roleGroups:
      default:
        replicas: 1
  workers:
    roleGroups:
      default:
        replicas: 1
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
  name: trino-tls (1)
spec:
  backend:
    autoTls: (3)
      ca:
        secret:
          name: secret-provisioner-trino-tls-ca
          namespace: default
        autoGenerate: true
---
apiVersion: hive.stackable.tech/v1alpha1
kind: HiveCluster
metadata:
  name: simple-hive-derby
spec:
  image:
    productVersion: 3.1.3
  clusterConfig:
    database:
      connString: jdbc:derby:;databaseName=/tmp/metastore_db;create=true
      user: APP
      password: mine
      dbType: derby
  metastore:
    roleGroups:
      default:
        replicas: 1
1 The name of (and reference to) the SecretClass
2 TrinoCatalog reference
3 TLS mechanism

CLI callout:

./trino.jar --debug --server https://172.18.0.3:31748 --keystore-path=<path-to-keystore.p12> --keystore-password=<password>

Via internal TLS

Internal TLS is for encrypted and authenticated communications between coordinators and workers. Since this applies to all the data send and processed between the processes, this may reduce the performance significantly.

---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCatalog
metadata:
  name: hive
  labels:
    trino: simple-trino
spec:
  connector:
    hive:
      metastore:
        configMap: simple-hive-derby
---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: simple-trino
spec:
  image:
    productVersion: "451"
  clusterConfig:
    tls:
      internalSecretClass: trino-internal-tls (1)
    authentication:
      - authenticationClass: trino-users (3)
    catalogLabelSelector:
      matchLabels:
        trino: simple-trino
  coordinators:
    roleGroups:
      default:
        replicas: 1
  workers:
    roleGroups:
      default:
        replicas: 1
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
  name: trino-internal-tls (1)
spec:
  backend:
    autoTls: (5)
      ca:
        secret:
          name: secret-provisioner-trino-internal-tls-ca (2)
          namespace: default
        autoGenerate: true
---
apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: trino-users (3)
spec:
  provider:
    static:
      userCredentialsSecret:
        name: trino-users (4)
---
apiVersion: v1
kind: Secret
metadata:
  name: trino-users (4)
type: kubernetes.io/opaque
stringData:
  admin: admin
---
apiVersion: hive.stackable.tech/v1alpha1
kind: HiveCluster
metadata:
  name: simple-hive-derby
spec:
  image:
    productVersion: 3.1.3
  clusterConfig:
    database:
      connString: jdbc:derby:;databaseName=/tmp/metastore_db;create=true
      user: APP
      password: mine
      dbType: derby
  metastore:
    roleGroups:
      default:
        replicas: 1
1 The name of (and reference to) the SecretClass
2 The name of (and reference to) the Secret
3 The AuthenticationClass for file based user control
4 The Secret containing user and password combinations in plaintext
5 TLS mechanism

Since Trino has internal and external communications running over a single port, this will enable the HTTPS port but not expose it. Cluster access is only possible via HTTP.

./trino.jar --debug --server http://172.18.0.3:31748 --user=admin