Couchbase User Authentication

      +
      A tutorial for configuring Couchbase user authentication and authorization using the Autonomous Operator.

      Tutorials are accurate at the time of writing but rely heavily on third party software. Tutorials are provided to demonstrate how a particular problem may be solved. Use of third party software is not supported by Couchbase. For further help in the event of a problem, contact the relevant software maintainer.

      Overview

      This tutorial describes how to use the Autonomous Operator to create authenticated users and bind them to specific roles to provide different levels of authorization.

      User authentication can be provided by Couchbase itself or an external LDAP service (such as OpenLDAP). The Autonomous Operator refers to Couchbase Authentication as the local domain, and LDAP Authentication as the external domain.

      Couchbase Authentication

      The local Couchbase domain performs internal password management and requires a password to be provided during user creation.

      Create a User Secret

      When using Couchbase for authentication, a Kubernetes Secret containing the user password needs to be created.

      The following command creates a secret with mypass set as the password:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: v1
      kind: Secret
      metadata:
        name: my-password-secret
      type: Opaque
      data:
        password: bXlwYXNz        # mypass
      EOF

      Create and Authorize a User

      Utilizing the Secret from the previous step, create a user and bind it to a set of roles which could be used for basic application development.

      The following command creates a new user, a new group containing the roles, and a new role binding to aggregate the the user and the group together:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseUser
      metadata:
        name: developer (1)
      spec:
        fullName: "Jane Doe"
        authDomain: local
        authSecret: my-password-secret (2)
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseGroup
      metadata:
        name: my-group (3)
      spec:
        roles: (4)
        - name: replication_admin
        - name: data_reader
          bucket: default (5)
        - name: data_writer
          buckets: (6)
            kind: CouchbaseBucket
            name: default
          scopes: (7)
            kind: CouchbaseScope
            name: seasia
          collections: (8)
            kind: CouchbaseCollection
            name: templates
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseRoleBinding
      metadata:
        name: my-group-binding (9)
      spec:
        subjects:
        - kind: CouchbaseUser
          name: developer
        roleRef:
          kind: CouchbaseGroup
          name: my-group
      EOF
      1 The new user, with username developer.
      2 The Secret from the previous step.
      3 The new group, with name my-group.
      4 The Couchbase roles that we want to assign to the new user.
      5 You can optionally specify a bucket name to apply the role against. This bucket need not be managed by the operator.
      6 You can also optionally specify bucket resources to apply the role against for managed buckets.
      7 In Couchbase server 7.0+, you can optionally specify scope resources to apply the role against.
      8 In Couchbase server 7.0+, you can optionally specify collection resources to apply the role against.
      9 The new role binding, with name my-group-binding, that binds the new user (developer) with the new group (my-group).

      To test that the new user was created and assigned the desired roles, connect to the Couchbase Web Console and log in as user developer with password mypass.

      # forward the ui port of a couchbase pod
      $ kubectl port-forward --namespace default <couchbase-pod-name> 8091:8091
      
      # open localhost:8091

      Create and Authorize Additional Users

      Additional users can be added to the development group with a similar set of roles. To authorize the additional users with the same roles as the user from the previous section, you only need to update the role binding to include the new users, since the group is already created.

      The following command creates two new users, and updates the role binding to bind them to the group that was created in the previous section:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseUser
      metadata:
        name: admin
      spec:
        fullName: "Joe Day"
        authDomain: local
        authSecret: my-password-secret
      ---
        apiVersion: couchbase.com/v2
        kind: CouchbaseUser
        metadata:
          name: security
        spec:
          fullName: "Bin Nash"
          authDomain: local
          authSecret: my-password-secret
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseRoleBinding
      metadata:
        name: my-group-binding
      spec:
        subjects: (1)
        - kind: CouchbaseUser
          name: developer
        - kind: CouchbaseUser
          name: admin
        - kind: CouchbaseUser
          name: security
        roleRef:
          kind: CouchbaseGroup
          name: my-group
      EOF
      1 Updates the role binding to include the two new users alongside the user from the previous section. The group now contains three users, and each user is bound to same set of roles.
      In this example, the two new users reference the same Secret as the user from the previous section. In production, you will want to create an individual secret for each user.

      At this point, you can modify the roles of all three users at once by updating the group. To do this, use the following command to edit the CouchbaseGroup resource and add the security_admin role:

      $ kubectl edit couchbasegroup my-group
      
      ...
      # Please edit the object below. Lines beginning with a '#' will be ignored,
      spec:
        roles:
        - name: replication_admin
        - bucket: '*'
          name: data_reader
        - bucket: default
          name: data_writer
        - name: security_admin

      LDAP Authentication

      Couchbase is able to delegate authentication to an external LDAP service. Using LDAP for authentication adds an additional level of security and places password management within an external domain.

      Running an OpenLDAP server

      The OpenLDAP service will be created using Helm. To seed the service with users and groups, a value override file needs to be created:

      $ echo "
      customLdifFiles:
        01-default-users.ldif: |-
          dn: ou=People,dc=example,dc=org
          objectClass: organizationalUnit
          ou: People
      
          dn: uid=jbrown,ou=People,dc=example,dc=org
          objectclass: top
          objectclass: person
          objectclass: organizationalPerson
          objectclass: inetOrgPerson
          uid: jbrown
          cn: James
          sn: Brown
          userPassword: password" > ldap-values.yaml

      Now run the OpenLDAP server with the custom values in ldap-values.yaml:

      # helm 3.1
      $ helm install my-release --set adminPassword=ldappassword -f ldap-values.yaml stable/openldap

      Couchbase will communicate with the OpenLDAP server using the service created by the Helm Chart.

      Run helm status to see the service endpoint:

      $ helm status my-release
      
      NOTES:
      OpenLDAP has been installed. You can access the server from within the k8s cluster using:
      
        my-release-openldap.default.svc.cluster.local:389

      The Couchbase service will also need to authenticate with OpenLDAP in order to query for user records and groups. Therefore, a Kubernetes secret will need to be created with the adminPassword which has been set to ldappassword:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: v1
      data:
        password: bGRhcHBhc3N3b3Jk      # ldappassword
      kind: Secret
      metadata:
        name: ldap-secret
      type: Opaque

      Edit the CouchbaseCluster Resource

      The LDAP configuration must be added to the CouchbaseCluster resource in order to authenticate external users. Add the OpenLDAP service endpoint as one of the hosts along with organizational information required to communicate with the service.

      apiVersion: couchbase.com/v2
      kind: CouchbaseCluster
      metadata:
        name: cb-example
      spec:
        image: couchbase/server:6.5.0
        security:
          rbac:
            managed: true
          ldap:
            hosts:
            - my-release-openldap.default.svc.cluster.local
            port: 389
            encryption: None
            bindDN: "cn=admin,dc=example,dc=org"
            bindSecret: ldap-secret
            userDNMapping:
              template: "uid=%u,ou=People,dc=example,dc=org"
         ...
      In production you will want to set encryption to StartTLS or TLS.

      After updating the CouchbaseCluster resource, you can test LDAP authentication from the Couchbase Web Console. Start by connecting to the Couchbase Web Console.

      # forward the ui port of a couchbase pod
      $ kubectl port-forward --namespace default <couchbase-pod-name> 8091:8091
      
      # open localhost:8091

      After logging in, go to the Security view, and click LDAP. Under "Test User Authentication", enter the username jbrown and the password password, and then click Test User Authentication. Couchbase Server will map the specified username to an LDAP DN, and perform authentication on the LDAP server. If your LDAP configuration is set up correctly, you’ll get a notification that the test was successful.

      Grant Roles to an LDAP User

      LDAP users are added to Couchbase using the same steps as local users except that the authDomain is set to external.

      Create a CouchbaseUser resource for the LDAP user:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseUser
      metadata:
        name: jbrown
      spec:
        fullName: "James Brown"
        authDomain: external
      EOF

      The next step is to bind the user to a group that contains the roles that you want the user to have. If you were to use the same groups and bindings from the local users section, the command would be as follows:

      $ cat << EOF | kubectl apply -f -
      ---
      apiVersion: couchbase.com/v2
      kind: CouchbaseRoleBinding
      metadata:
        name: my-group-binding
      spec:
        subjects:
        - kind: CouchbaseUser
          name: developer
        - kind: CouchbaseUser
          name: admin
        - kind: CouchbaseUser
          name: security
        - kind: CouchbaseUser
          name: jbrown
        roleRef:
          kind: CouchbaseGroup
          name: my-group
      EOF

      If you followed this setup, the LDAP user has the same roles as the other uses, even though it relies on a different authentication path (external vs local).

      You can test authentication/authorization by logging into the Couchbase Web Console with the username jbrown and password password.

      Further Reading