Authentication with OpenLDAP

The Stackable platform supports user authentication with LDAP in multiple products. This page guides you through setting up the configuration necessary to use an existing LDAP installation with Stackable supported products. You can learn more about authentication in the Stackable Platform on the concepts page.

Prerequisites:

  • a k8s cluster available, or kind installed

  • stackablectl installed

  • basic knowledge of how to create resources in Kubernetes (i.e. kubectl apply -f <filename>.yaml) and inspect them (kubectl get or a tool like k9s)

Setup

Before configuring LDAP you need to set up some services to configure, as well as an LDAP server to use for authentication. This tutorial is about learning how to configure LDAP, so there won’t be detailed instructions on how to set up all of this, instead the tutorial uses the stackablectl stacks command.

Superset and Trino Stack

This command will install the latest Stackable release for you, and set up the trino-superset-s3 Stack. It contains a Superset instance connected to a Trino instance, and all their dependencies (Minio S3, PostgreSQL). Later in this guide, a Superset and Trino instance will be configured to use LDAP.

If you do not have a Kubernetes cluster already, add the --cluster kind (or -c kind) flag to let stackablectl deploy one for you.

stackablectl stack install trino-superset-s3

This command will take a few minutes to complete.

The stack installed here is used in the trino-taxi-data demo. Click the link to learn more.

Inspect

Before starting to add configuration to your Stackable cluster, inspect what the command above has set up in your Kubernetes cluster.

Use stackablectl stacklets list to find the endpoints of Superset and Trino and open their web interfaces in the browser.

You can log into Superset with user admin and password adminadmin, and into Trino with user admin and password adminadmin.

These are the current users defined in Superset’s and Trino’s internal user management. Later you will see that these users cannot be used for authentication anymore after LDAP authentication has been enabled.

OpenLDAP Stack

Install another Stack, the tutorial-openldap.

stackablectl stack install tutorial-openldap

Inspect

Look at the Pod definition of the openldap-0 Pod, it contains the environment settings

LDAP_ADMIN_USERNAME:      ldapadmin
LDAP_ADMIN_PASSWORD:      ldapadminpassword
LDAP_USERS:               alice,bob
LDAP_PASSWORDS:           alice,bob

ldapadmin is the admin or bind user, and ldapadminpassword is the password that belongs to that user. alice and bob (and their respective passwords) are the only two users defined in the LDAP instance. You will use this information later to configure LDAP.

Steps

Now that you have a couple of data products as well as the LDAP server installed, you can start configuring the products to use LDAP. The following image shows the parts that are already there in blue and the parts you will add in green:

image$openldap tutorial.drawio

The tutorial has 3 steps:

  1. Configure an AuthenticationClass (as well as SecretClass and Secret) with this LDAP installation

  2. Update the SupersetCluster to use the AuthenticationClass to authenticate users

  3. Update the TrinoCluster to use the AuthenticationClass to authenticate users

Configure LDAP

The AuthenticationClass is the main resource required to configure the products, but it depends on some other resources. Below you will create a Secret, SecretClass and the AuthenticationClass. Use kubectl apply to deploy the manifests shown below.

If you’re having problems here, install the openldap stack instead of tutorial-openldap which comes with an already configured AuthenticationClass ready to use. You can then skip to configuring superset.

First, create a secret that contains the LDAP bind credentials which products can use to authenticate with LDAP:

---
apiVersion: v1
kind: Secret
metadata:
  name: openldap-bind-credentials
  labels:
    secrets.stackable.tech/class: openldap-bind-credentials  (1)
stringData:
  user: cn=ldapadmin,dc=example,dc=org  (2)
  password: ldapadminpassword           (3)
1 The annotation which SecretClass this secret belongs to
2 The LDAP bind user that was provided by the tutorial-ldap Stack
3 The corresponding password

Notice the SecretClass annotation. Create the SecretClass next:

---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
  name: openldap-bind-credentials  (1)
spec:
  backend:
    k8sSearch:
      searchNamespace:
        pod: {}  (2)
1 The name of the SecretClass we are creating that is referred to by the Secret
2 This determines the namespace in which the referenced Secret will be looked for. In this case it searches for a Secret in the same namespace as the product runs in. See the documentation of SecretClass

This level of indirection is necessary, because the AuthenticationClass is cluster-scoped but Secrets are not.

Now you can create the AuthenticationClass openldap which references the SecretClass:

---
apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
  name: openldap  (1)
spec:
  provider:
    ldap:
      hostname: openldap.default.svc.cluster.local  (2)
      searchBase: ou=users,dc=example,dc=org
      bindCredentials:
        secretClass: openldap-bind-credentials  (3)
      port: 1636
      tls:
        verification:
          server:
            caCert:
              secretClass: openldap-tls
1 The name of the AuthenticationClass, which needs to be referenced later
2 The hostname in this case is the Service at which the OpenLDAP is running, inside of Kubernetes.
3 Here the SecretClass name is referenced

Remember the name of the AuthenticationClass (openldap), you will use it in the next steps when configuring the products.

Add LDAP authentication to Superset

To make Superset use your new LDAP AuthenticationClass, you have to update the SupersetCluster definition. A SupersetCluster named superset is already installed by the stack.

Fetch the existing SupersetCluster defintion from the Kubernetes API server and save it into a superset.yaml file:

kubectl get superset superset -o yaml > superset.yaml
The superset.yaml file should look similar to this
---
apiVersion: superset.stackable.tech/v1alpha1
kind: SupersetCluster
metadata:
  name: superset
  ...
spec:
  image:
    productVersion: ...
  clusterConfig:
    listenerClass: ...
    credentialsSecret: superset-credentials
    mapboxSecret: ...
  nodes:
    roleGroups:
      default:
        replicas: 1
  ...

You can now delete the SupersetCluster, you recreate it later with the new configuration:

kubectl delete superset superset

Modify your superset.yaml to include this new authentication property under the spec.clusterConfig:

spec:
  clusterConfig:
    authentication:                   (1)
      - authenticationClass: openldap (2)
        userRegistrationRole: Admin   (3)
1 The new authentication configuration section which configures how Superset is authenticating users
2 The authenticationClass property is referencing the AuthenticationClass openldap you created earlier
3 The default Superset role that users should be assigned to when they log in. Any user will be an Admin
Your superset.yaml should now look similar to this
---
apiVersion: superset.stackable.tech/v1alpha1
kind: SupersetCluster
metadata:
  name: superset
  ...
spec:
  image:
    productVersion: ...
  clusterConfig:
    authentication:
      - authenticationClass: openldap
        userRegistrationRole: Admin
    listenerClass: ...
    credentialsSecret: superset-credentials
    mapboxSecret: ...
  nodes:
    roleGroups:
      default:
        config:
  ...

Now deploy the updated superset cluster:

kubectl apply -f superset.yaml

Connect to superset as before, and try logging in again with username admin and password adminadmin, Superset will not accept these credentials anymore. You now have to use LDAP credentials to log in. The OpenLDAP you installed earlier comes with two users, alice (password alice) and bob (password bob). Log in with any of these users and Superset will accept.

Add LDAP configuration to Trino

Trino is configured very similarly to Superset.

Fetch the existing TrinoCluster definition from the Kubernetes API server and save it into a trino.yaml file:

kubectl get trino trino -o yaml > trino.yaml
The trino.yaml file should look similar to this
---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: trino
  ...
spec:
  image:
    productVersion: ...
  clusterConfig:
    authentication:
      - authenticationClass: trino-users
    authorization:
      opa:
        configMapName: opa
        package: trino
    catalogLabelSelector:
    ...
  workers:
    ...
  coordinators:
    ...
  ...

You can now delete the TrinoCluster. you recreate it later with the new configuration:

kubectl delete trino trino

Replace the trino-users AuthenticationClass in your trino.yaml with the openldap AuthenticationClass:

spec:
  clusterConfig:
    authentication:
      - authenticationClass: openldap (1)
1 Switch the authenticationClass to the AuthenticationClass openldap you created earlier
Your trino.yaml should now look similar to this
---
apiVersion: trino.stackable.tech/v1alpha1
kind: TrinoCluster
metadata:
  name: trino
  ...
spec:
  image:
    productVersion: ...
  clusterConfig:
    authentication:
      - authenticationClass: openldap
    authorization:
      opa:
        configMapName: opa
        package: trino
    catalogLabelSelector:
    ...
  workers:
    ...
  coordinators:
    ...
  ...

Now deploy the updated Trino cluster:

kubectl apply -f trino.yaml

Again, like with Superset, connect to Trino now (make sure that the StatefulSets are running). You will notice that the admin user cannot be used anymore, but the LDAP users alice and bob work!

Bonus: Reconfigure OPA to use the new LDAP users

This is a bonus step, and if you want you can skip straight to the next section: Log in with the new LDAP credentials

This step is not required for authentication by itself. But the demo stack you installed comes with an authorization configuration for Trino as well. Authorization on the platform is done using the Stackable Operator for OPA (OpenPolicyAgent).

Fetch the snippet as before:

kubectl get cm trino-opa-bundle -o yaml > trino-opa-bundle.yaml

Apply this patch:

data:
  trino.rego: |
    package trino

    import future.keywords.in

    default allow = false

    allow {
      is_alice
    }
    extended[i] {
      some i
      input.action.filterResources[i]
      is_alice
    }

    is_alice() {
      input.context.identity.user == "alice"
    }

And apply the new bundle that lets alice do everything and denies bob everything:

kubectl apply -f trino-opa-bundle.yaml

The OPA Operator will automatically detect the change and update the Trino authorization bundle.

Log in with the new LDAP credentials

Congratulations! You have configured Superset and Trino to use LDAP for authentication.

Log in with the LDAP user credentials alice:alice or bob:bob into Superset and Trino. Note also that the previously used admin credentials no longer work.

If you skipped the OPA step, you will be able to log into Trino, but running queries will not work, as the LDAP users are not authorized to do so. If you did do this step, running queries with the LDAP users will also work.

That concludes the tutorial!

Summary

To summarize, you have done the following:

  • Written an AuthenticationClass for an existing LDAP server. The credentials are stored in a Secret with a SecretClass that is referenced in the AuthenticationClass.

  • Adapted the SupersetCluster spec to include the reference to the LDAP AuthenticationClass.

  • Adapted the TrinoCluster spec to include the reference to the AuthenticationClass.

The LDAP connection details only need to be written down once, in the AuthenticationClass. Making a product use this AuthenticationClass is then done by referencing the AuthenticationClass, so the configuration for LDAP is all in a single resource.