Authenticate requests against membership information that is stored in a Lightweight Directory Access Protocol (LDAP) server.

This feature is available with a Gloo Mesh Gateway license only.

About LDAP

The Lightweight Directory Access Protocol (LDAP) is an open protocol that you can use to store and retrieve hierarchically structured data over a network. Many enterprises use LDAP to centrally store and secure organizational information. In particular, LDAP is often used for membership directories. You might set up LDAP to store information such as the following:

You can deploy an LDAP server to your Kubernetes cluster. Then, use a Gloo Mesh external auth policy to authenticate users and control access based on their group membership details in the LDAP server.

Want to learn more about LDAP? Try out this LDAP tutorial by Digital Ocean.

How does LDAP work with Gloo Mesh?

Upon receiving an authentication request that uses LDAP, Gloo Mesh performs the following steps.

  1. Gloo Mesh looks for a Basic Authentication header on the request to extract the username (uid) and credentials (userPassword).
  2. If the header is not present, a 401 response is returned.
  3. If the header is present, Gloo Mesh extracts the username from the basic auth header. Then, it builds the distinguished name (DN) for the user entry by substituting the username from the header for the %s placeholder in the LDAP userDnTemplate setting.
    To prevent injection attacks, Gloo Mesh removes special characters from the username before continuing to the next bind step.
  4. Gloo Mesh performs a BIND operation with the LDAP server, using the DN for the user entry from the previous step.
  5. If the bind operation fails, a 401 response is returned. This response means that the user could not be found or the credentials are incorrect.
  6. Gloo Mesh issues a search operation for the user entry (with a base scope). In the user entry, Gloo Mesh looks for an attribute with a name equal to membershipAttributeName.
  7. Gloo Mesh checks if one of the values for the attribute matches one of the allowedGroups in the policy. If so, Gloo Mesh completes the request. Otherwise, Gloo Mesh returns a 403 response. This response means that although the user can be authenticated, the user does not have the appropriate permissions to complete the request.

Before you begin

  1. Complete the demo setup to install Gloo Mesh, Istio, and Bookinfo in your cluster.

  2. Make sure that you have the ldapsearch CLI tool on your local machine. This tool is part of the default developer tools in macOS. You can check if you have the tool by running the following command to print the usage details. To install LDAP and Helper utilities, see this Digital Ocean guide.

    ldapsearch --help
  3. Create the Gloo Mesh resources for this policy in the management and workload clusters.

    The following files are examples only for testing purposes. Your actual setup might vary. You can use the files as a reference for creating your own tests.

    1. Download the following Gloo Mesh resources:

    2. Apply the files to your management cluster.

      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-1.yaml --context ${MGMT_CONTEXT}
      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-2.yaml --context ${MGMT_CONTEXT}
      kubectl apply -f workspace_gloo-mesh_anything.yaml --context ${MGMT_CONTEXT}
    1. Download the following Gloo Mesh resources:

    2. Apply the files to your workload cluster.

      kubectl apply -f virtual-gateway_bookinfo_north-south-gw.yaml --context ${REMOTE_CONTEXT1}
      kubectl apply -f workspace-settings_bookinfo_anything.yaml --context ${REMOTE_CONTEXT1}
  4. Send a request to verify that you can reach the ratings app without authorization. By default Gloo Mesh allows any request on routes that do not specify authentication.

    curl -v ${INGRESS_GW_IP}/ratings/1 -H "Host: www.example.com"

    Example output:


Deploy an LDAP server

Before you can create an LDAP external auth policy, you must have an LDAP server. The following example configures a simple set of users and groups, and deploys the LDAP server to your cluster.

  1. Download the sample LDAP setup script.

  2. Review what the sample LDAP setup script does. For in-depth information, see About the LDAP setup script. In short, the script sets up LDAP users and groups, as well as creates the following Kubernetes resources:

    • A configmap with the LDAP server setup configuration.
    • A deployment to run OpenLDAP.
    • A service to provide access to the deployment.
  3. Make the downloaded script executable.

    chmod +x setup-ldap.sh
  4. Set your Kubernetes context to the cluster that you want to deploy the LDAP server to and create the external auth policy in.

    kubectl config use-context ${REMOTE_CONTEXT1}
  5. Run the LDAP setup script. The script accepts an optional string argument to specify the namespace to create the resources in. Otherwise, you can omit the argument to create the resources in the default namespace.


    Example output:

    No namespace provided, using default namespace
    Creating configmap with LDAP server bootstrap config...
    configmap/ldap created
    Creating LDAP service and deployment...
    deployment.apps/ldap created
    service/ldap created
  6. Enable port-forwarding on the deployment so that you can test the LDAP server.

    kubectl port-forward deployment/ldap 8088:389
  7. In a new tab in your terminal, search for the distinguished names (DNs) of all entries in the solo and io domain components (DCs). For more information about this command, see the LDAP docs.

    ldapsearch -H ldap://localhost:8088 -D "cn=admin,dc=solo,dc=io" -w "solopwd" -b "dc=solo,dc=io" -LLL dn

    Example output:

    dn: dc=solo,dc=io
    dn: cn=admin,dc=solo,dc=io
    dn: ou=people,dc=solo,dc=io
    dn: uid=marco,ou=people,dc=solo,dc=io
    dn: uid=rick,ou=people,dc=solo,dc=io
    dn: uid=scottc,ou=people,dc=solo,dc=io
    dn: ou=groups,dc=solo,dc=io
    dn: cn=developers,ou=groups,dc=solo,dc=io
    dn: cn=sales,ou=groups,dc=solo,dc=io
    dn: cn=managers,ou=groups,dc=solo,dc=io

Good job, now you have an LDAP server running! Continue to Configure an external auth policy with LDAP.

About the LDAP setup script

The LDAP setup script sets up a basic LDAP server with a few different users and groups. This setup includes the Kubernetes resources to create in the cluster.

Click this paragraph to expand the full sample script.

The root of the LDAP directory hierarchy is the dc=solo,dc=io entry, which has two child entries for users and groups.

ou=groups,dc=solo,dc=io is the parent entry for user groups in the organization. It has three groups:

  • cn=developers,ou=groups,dc=solo,dc=io
  • cn=sales,ou=groups,dc=solo,dc=io
  • cn=managers,ou=groups,dc=solo,dc=io
03_people.ldif: |
  # Create a parent 'people' entry
  dn: ou=people,dc=solo,dc=io
  objectClass: organizationalUnit
  ou: people
  description: All solo.io people

  # Add 'marco'
  dn: uid=marco,ou=people,dc=solo,dc=io
  objectClass: inetOrgPerson
  cn: Marco Schwarz
  sn: Schwarz
  uid: marco
  userPassword: marcopwd
  mail: marco.schwarz@solo.io

  # Add 'rick'
  dn: uid=rick,ou=people,dc=solo,dc=io
  objectClass: inetOrgPerson
  cn: Rick Duke
  sn: Duke
  uid: rick
  userPassword: rickpwd
  mail: rick.duke@solo.io

  # Add 'scottc'
  dn: uid=scottc,ou=people,dc=solo,dc=io
  objectClass: inetOrgPerson
  cn: Scott Crawley
  sn: Crawley
  uid: scottc
  userPassword: scottcpwd
  mail: scott.crawley@solo.io

ou=people,dc=solo,dc=io is the parent entry for people in the organization. It has the following entries:

  • uid=marco,ou=people,dc=solo,dc=io
  • uid=rick,ou=people,dc=solo,dc=io
  • uid=scott,ou=people,dc=solo,dc=io
04_groups.ldif: |+
  # Create top level 'group' entry
  dn: ou=groups,dc=solo,dc=io
  objectClass: organizationalUnit
  ou: groups
  description: Generic parent entry for groups

  # Create the 'developers' entry under 'groups'
  dn: cn=developers,ou=groups,dc=solo,dc=io
  objectClass: groupOfNames
  cn: developers
  description: Developers group
  member: uid=marco,ou=people,dc=solo,dc=io
  member: uid=rick,ou=people,dc=solo,dc=io
  member: uid=scottc,ou=people,dc=solo,dc=io

  # Create the 'sales' entry under 'groups'
  dn: cn=sales,ou=groups,dc=solo,dc=io
  objectClass: groupOfNames
  cn: sales
  description: Sales group
  member: uid=scottc,ou=people,dc=solo,dc=io

  # Create the 'managers' entry under 'groups'
  dn: cn=managers,ou=groups,dc=solo,dc=io
  objectClass: groupOfNames
  cn: managers
  description: Managers group
  member: uid=rick,ou=people,dc=solo,dc=io

The user credentials and memberships are summarized in the following table.

Username Password Member of developers Member of sales Member of managers
marco marcopwd
rick rickpwd
scott scottpwd

Configure an external auth policy with LDAP

Create the external auth policy with LDAP.

You can do the following steps in a different order, depending on when you want the policy to take effect. For example, you might want the policy to always take effect as soon as the route is created. To do so, you can create the policy before you add the route to the route table.
  1. Create an external auth server to use for your policy.
    kubectl --context ${REMOTE_CONTEXT1} apply -f - <<EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: ExtAuthServer
      name: ext-auth-server
      namespace: bookinfo
          cluster: cluster-1
          name: ext-auth-service
          namespace: gloo-mesh
          name: http2
  2. Create a route table for the ratings app and external auth policy. Note that the route table selects the virtual gateway that you created before you began, and routes to the ratings service.
    kubectl --context ${REMOTE_CONTEXT1} apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
      name: bookinfo
      namespace: bookinfo
        expose: "true"
        - '*'
        - name: north-south-gw
          namespace: bookinfo
          cluster: cluster-1
      workloadSelectors: []
        - name: ratings
            ldap: "true"
          - uri:
              prefix: /ratings
            - ref:
                name: ratings
                namespace: bookinfo
  3. Create an external auth policy that uses the LDAP server.
    kubectl --context ${REMOTE_CONTEXT1} apply -f - <<EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: ExtAuthPolicy
      name: ratings-ldap
      namespace: bookinfo
      - route:
            ldap: "true"
          name: ext-auth-server
          namespace: bookinfo
          cluster: cluster-1
          - ldap:
              address: "ldap://ldap.default.svc.cluster.local:389"
              userDnTemplate: "uid=%s,ou=people,dc=solo,dc=io"
              membershipAttributeName: memberOf
              - "cn=managers,ou=groups,dc=solo,dc=io"

Review the following table to understand this configuration. For more information, see the API reference.

Setting Description
applyToRoutes Configure which routes to apply the policy to, by using labels. The label matches the app and the route from the route table. If omitted, the policy applies to all routes in the workspace.
server The external auth server to use for the policy.
ldap Configure the LDAP server details.
address The address of the LDAP server that Gloo Mesh queries when a request matches the policy. This example uses the Kubernetes DNS name and port of the LDAP service that you deployed in the default namespace.
userDnTemplate The template string for Gloo Mesh to build the DNs of the user entry to authenticate and authorize. The string must have a single occurrence of the %s placeholder. This placeholder is used to substitute the value from the request header that you want to look for, such as the user ID (uid) in this example. In this example, the template matches the format of the user entry DNs in the config map.
membershipAttributeName A case-insensitive name of the attribute with the names of the groups that a user entry is a member of. If not set, the default value memberOf is used. In the example, the config map sets memberOf automatically for each user entry that is in a group.
allowedGroups The DNs of the user groups that are allowed to access services that are protected by this policy. In this example, only members of "cn=managers,ou=groups,dc=solo,dc=io" group can get successful responses.

Verify the external auth LDAP policy

To test the LDAP policy, make a series of requests as different users. The following table is based off the users that you created in your LDAP config map. The username and password are encoded to base 64 in the format username:password so that you can pass them in a basic auth header.

Username Password Basic auth header Notes
marco marcopwd Authorization: Basic bWFyY286bWFyY29wd2Q= Member of developers group
rick rickpwd Authorization: Basic cmljazpyaWNrcHdk Member of developers and managers groups
john doe Authorization: Basic am9objpkb2U= Unknown user, not a member of any group
  1. Send a request to the ratings app without any auth header. Now, the request is blocked with a 401 Unauthorized response.

    curl -v ${INGRESS_GW_IP}/ratings/1 -H "Host: www.example.com"
  2. Repeat the previous step with the credentials of the unknown member, john. The request is blocked with the same 401 Unauthorized response.

    curl -v ${INGRESS_GW_IP}/ratings/1 -H "Host: www.example.com" -H "Authorization: Basic am9objpkb2U="
  3. Try a request with the credentials of a known member, marco. This user is a member of the developers group, but the LDAP policy only grants permission to members of the managers group. The request is blocked, but this time with a 403 Forbidden response to indicate the lack of permissions.

    curl -v ${INGRESS_GW_IP}/ratings/1 -H "Host: www.example.com" -H "Authorization: Basic bWFyY286bWFyY29wd2Q="
  4. Finally, send a request with the credentials of rick, who is a member of the managers group and meets the LDAP policy requirements.

    curl -v ${INGRESS_GW_IP}/ratings/1 -H "Host: www.example.com" -H "Authorization: Basic cmljazpyaWNrcHdk"

    The request succeeds!

    HTTP/1.1 200 OK


To remove the LDAP server that you created, run the following commands.

kubectl delete --context ${REMOTE_CONTEXT1} configmap ldap
kubectl delete --context ${REMOTE_CONTEXT1} deployment ldap
kubectl delete --context ${REMOTE_CONTEXT1} service ldap