Jenkins LDAP Authentication

Continuing on my journey through centralizing my authentication for a number of services, I come to my Jenkins instance. This was setup recently to handle CI/CD on some of my personal projects, and has been working extremely well on automated build/test/deploy. Since none of the software it supports is going anywhere anytime soon, I decided to add the instance to the grouping of services going to LDAP for authentication. Setting up Jenkins with LDAP is a relatively straight forward process. It requires a few plugins to support it fully (authentication, group based authorization). The difficulty comes in authorization, as the role-based authorization strategy plugin isn’t as well documented as one would hope. It is at least not too hard to work through and works as intended.

Plugins to Use

Setting it Up

All of the plugins were used in this guide, however for just simple LDAP authentication, only the LDAP plugin is needed. The other plugins are only needed to support role-based authorization. By default, all users who log into Jenkins are treated as administrators. The role-based authorization plugin allows us to limit the rights of different accounts based off of their LDAP groups.

Determining the Group Attributes

While reading the LDAP plugin documentation, I noticed the following interesting snippet.

OpenLDAP with the memberof overlay active (untested, and as memberof is an operational attribute in OpenLDAP it must be explicitly requested, so likely some hacking of LDAPSecurityRealm.groovy required)

LDAP Plugin Documentation

So according to this, the memberOf attribute in OpenLDAP can be used for getting a users group memberships, it is not the most effective way to do so for Jenkins, and isn’t well supported. For this reason we decided to go the other way, see which users belong to which groups. To start out, I ran an LDAP search on the administrators group to see what attribute name the membership would be under, and the class of LDAP object the group belongs to.

Administrator@ucs:~$ ldapsearch -xLLL -b cn=administrators,cn=Builtin,dc=rapternet,dc=us -D uid=auth-grafana,cn=users,dc=rapternet,dc=us -W \* +
Enter LDAP Password:
dn: cn=Administrators,cn=Builtin,dc=rapternet,dc=us
sambaGroupType: 2
cn: Administrators
objectClass: top
objectClass: univentionGroup
objectClass: posixGroup
objectClass: univentionObject
objectClass: sambaGroupMapping
univentionObjectType: groups/group
sambaSID: S-1-5-32-544
gidNumber: 5052
univentionGroupType: -2147483643
description: Administrators have complete and unrestricted access to the compu
 ter/domain
structuralObjectClass: posixGroup
entryUUID: bc1e8154-1220-1036-9551-016bd08a0cd5
creatorsName: cn=admin,dc=rapternet,dc=us
createTimestamp: 20160918192042Z
memberUid: Administrator
uniqueMember: cn=domain admins,cn=groups,dc=rapternet,dc=us
uniqueMember: cn=enterprise admins,cn=groups,dc=rapternet,dc=us
uniqueMember: uid=administrator,cn=users,dc=rapternet,dc=us
entryCSN: 20160918192044.102359Z#000000#000#000000
modifiersName: cn=admin,dc=rapternet,dc=us
modifyTimestamp: 20160918192044Z
entryDN: cn=Administrators,cn=Builtin,dc=rapternet,dc=us
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE

From the output, we can see that the object class for our group is posixGroup, which is a part of the default filters for the Jenkins LDAP plugin, and the membership attribute is uniqueMember, which is also a part of the default filters in Jenkins. This is lucky for us as its less configuration to have to do to get our centralized authentication working.

Setting up the LDAP Plugin

The LDAP plugin settings are located under Manage Jenkins → Configure Global Security. The security realm can then be changed from “Jenkins own user database” to “LDAP”. Make sure that LDAP searches are working properly using the “Test LDAP settings” button before saving the settings changes. Click the “Advanced Server Configuration” button to show the full set of settings for the LDAP plugin.

The LDAP plugin is straight forward to setup. The only feature I was missing was to allow self signed certs (or to not check the certificates) when using LDAPS. Due to this, and my lack of signed certificates for my LDAP server, I used the unencrypted connection. For an encrypted connection, make sure you have your certificates in order and use an LDAPS url to tell Jenkins to encypt the connection.

  • Server: ldap://ucs.rapternet.us:7389
  • Root DN: dc=rapternet, dc=us
  • User search base: blank
  • User search filter: uid={0}
  • Group search base: blank
  • Group search filter: blank
  • Group membership: search for LDAP groups containing user: blank
    • blank by default goes to: (| (member={0}) (uniqueMember={0}) (memberUid={1}))
    • This covers the univention uniqueMember field on the groups
    • This also avoids memberOf issues that occur with the plugin that require extra work to go around
  • Manager DN: uid=jenkins-auth,cn=users,dc=rapternet,dc=us
  • Password: stronk_password
  • Display name LDAP attribute: displayname
  • Email address LDAP attribute: mailPrimaryAddress

All of the inputs left blank were to use the default values for them. These were found to cover the attributes in UCS and were found to work (so why complicate it).

As far as the group membership goes, I did try to use memberOf in the most basic sense to no success. The LDAP plugin didn’t request the memberOf attribute when searching for users, so without extra work, I couldn’t use that to flag what groups my user was a part of. I setup Jenkins to search for users within my groups using the uniqueMember attribute. Also ensure that your search user has a strong password to login with.

Our administrator test reveals that groups are working now that we are using the uniqueMember attribute on the groups themselves.

Login
Authentication: failed for user "administrator" with empty password
Lookup
User lookup: successful
User ID: administrator
User Dn: uid=Administrator,cn=users,dc=rapternet,dc=us
User Display Name: Administrator
User email: administrator@rapternet.us
LDAP Group membership:

    Domain Admins
    piwigo_admins
    Enterprise Admins
    Group Policy Creator Owners
    Schema Admins
    piwigo_webmasters
    piwigo_users
    Domain Users
    Administrators
    DC Backup Hosts

LDAP Group lookup: successful (10 groups)

Role-Based Authorization Strategy

I installed the role-based authorization strategy plugin as a way to provide some authorization based on the LDAP groups on my univention server. This was simple enough to setup after some of my earlier work with Portainer and Grafana.

Authorization settings can be found under Manage Jenkins → Configure Global Security in the “Authorization” section. The default uption is that logged in users can do everything, essentially making all users admins. We’re going to change that to Role-Based strategy. This will allow us to change how much access different LDAP groups will have over the Jenkins instance. After saving the settings to use the role-based strategy, the settings will show up in the Manage Jenkins panel, this time at the bottom under “Manage and Assign Roles”.

Under Mange and Assign Roles, there are a few panels:

  • Manage Roles
    • Create new roles
    • Determine the access for each role
  • Assign Roles
    • Assign LDAP groups to each grouping of roles (Global, Item, Node)
  • Role-Strategy Macros Info
    • I didn’t utilize these settings

Under the Manage roles panel, I setup two sets of roles in Jenkins, viewer, and administrator. My viewer role was given a global read only in the overall set of options. My admin role was given every checkbox concievable in the global roles. I created an item_admin and node_admin roles as well, each with “.*” for the pattern, and every access available. These need to be unique names for each grouping.

Under the Assign Roles panel, I provided anonymous logins the viewer role, and added my administrators group to use the admin role. My Jenkins instance is only accessible from my intranet (and will forever stay that way), so I’m not worried about a local user being able to view my builds. I wanted at least a basic way to spy on whats going on quickly if needed. Adding a new LDAP group is easy enough, just add in the name to the User/Group to add, click the add button, and pick the checkboxes to each role the group should have.

In the future, I will likely add a less privileged user for my general user account, being able to manage projects but not resources. This would be another group to add in both LDAP and in this panel, providing the group in Jenkins a subset of the permissions.

Since I could verify that my user was seen in the group in Jenkins, I guessed that this would work right based on the documentation, though I wish they had a little checker widget that first log out log in is a bit stressful if that role didn’t work right. Luckily it did work correctly and my administrator user could still administrate the Jenkins installation after enabling the role based auth plugin.

Authorize Plugin

Under the Manage Jenkins → Configure Global Security, there is an “Access Control for Builds” section that this plugin handles. For my case, I want builds to all be run as the system as the system user is the user with access to the docker.sock for building with. I set this as such in my security settings, though Jenkins will complain about this setting as it isn’t the most secure option available.

Conclusion

Setting up the centralized authentication on Jenkins was also pretty straight forward. The difficulty came in the Role-Based Authorization plugin and determining if it was setup correctly (lack of a widget to verify its working correctly). For this reason, I would only suggest setting that up if needed (at the time of this writing, the plugin is also not currently supported, which has me nervous). This worked out well on my Jenkins instance and I’ve been using my LDAP users on it since configuring it. The Role-Based Authorization and LDAP authentication work well.