September 26, 2025

Onboarding GitLab On-Premise with SailPoint Identity Security Cloud

Introduction

When a client asked me to connect GitLab on-premise with SailPoint Identity Security Cloud (ISC), I struggled to find online references addressing how to perform the integration. Now that I have completed the application onboarding, I am blogging about my process to guide other developers taking on this task.

After reviewing the requirements provided by the client, I will discuss authentication for the initial connection. Next, I will dive into the setting up object aggregations, reviewing different milestones I passed before developing a solution encompassing all the requirements. I will discuss the custom rules implemented for each HTTP Operation before finally exploring additional use cases for further expansion of the implementation. 

Client Requirements

Our client wanted to use SailPoint’s certification functionality to audit GitLab users who have permission to deploy code to production. In GitLab, these users are members of privileged groups. To differentiate the abilities of group members, our client wanted to review the access levels assigned to users. Of the several access levels in GitLab, our client only wanted to review developers, maintainers, and owners. Additionally, subgroups, which allow users to gain capabilities when they are members of parent groups, should appear as entitlements on the user’s identity.

Initial Connection

SailPoint offers VA-based and SaaS connectors. SaaS connectors are designed for internet-accessible cloud applications, while VA connectors suit on-premise applications which utilize an internal network. Of the available options, the Web Services connector is the most suitable to interface with GitLab’s REST API for an internal GitLab instance.After determining the connector type, the next milestone will be authenticating into GitLab from the SailPoint connector.

I first sought to set up the Web Services connector using the OAuth 2.0 authentication option, due to the security benefits it has over a standard API token. However, GitLab and the Web Services connector do not have any OAuth 2.0 protocols in common. OAuth 2.0 from the Web Services connector only supports: Password Grant Type, Client Credentials, Refresh Token, JWT Bearer Token, and SAML Bearer Assertion paths, whereas GitLab supports PKCE, Authorization code, Resource Owner Password Credentials, and Device Authorization Grant flows. Therefore, the most effective way to handle authentication is with an API token generated on the GitLab side. 

HTTP Operations

Overview

After finishing the Base Configuration and Connection Settings sections on the Web Services connector, the next step will require configuring the HTTP Operations portion. HTTP Operations perform API calls from the Web Services connector, allowing the data returned by an API call to be directly usable by SailPoint. Overall, I needed three HTTP Operations in total, to include a test connection, group aggregation, and account aggregation. 

Test Connection

Starting with a Test Connection operation type allows validation of the Base Connection and Connection Settings sections, essentially ensuring that SailPoint can authenticate to and receive data from GitLab. For this operation type, I utilized the Version API, which only requires a valid Private Access Token and no additional parameters. Using the GET /version endpoint for a test connection operation type limits the scope of potential errors to authentication or misconfiguration of previous sections, rather than data sent within the API call. 

Group Aggregation

A group aggregation HTTP Operation can be configured to call GET /groups, which will return a list of all groups, with information like group id, name, description, path, parent group id, and more.  

The client required access level information per user, and visibility into subgroups. To meet these requirements, I needed to pull in distinct groups with access levels indicated, so later the users could be appropriately correlated as group members. Due to the complexity, I developed a simple solution first before implementing a custom rule that allowed for all requirements to be met.

Milestone 1: Groups Queried without Access Levels

Groups can be queried for aggregation without any custom rules. GitLab limits the page size to 100 groups returned at a time, so starting with ensuring all groups can be imported helps test paging logic. This setup was insufficient because there was no way to distinguish access levels for each group, because access rights per user is not part of the Group API response data. 

Final Milestone: Custom Rule to Incorporate Access Levels

Building onto the first milestone, I developed a Web Service After Operation Rule, which allows developers to take all data returned by an API call and modify it before returning it to ISC.  For each group returned, and for each access level our client wanted represented, I duplicated the basic group data and added new fields to indicate which access level the entitlement represented. For example, Group A expanded into Group A – Developer, Group A – Maintainer, and Group A – Owner. The expanded groups were stored in a list and then returned to ISC. 

Account Aggregation

An account aggregation HTTP Operation should call the GET /users endpoint. The API will return account information such as account id, username, name, account state, email, and more.  This API call will be referred to as the parent, as the next sections discuss child HTTP operations.

In addition to account information, our client wanted to see all group memberships each user has, subgroups each user inherits, and access levels for both tiers of memberships. First, I implemented the simplest solution to pull all groups into SailPoint. Next, I implemented a rule that could not account for subgroup membership, but does associate users with access levels. Lastly, I developed a more complex customization that could properly read subgroup access.

Milestone 1: Users Queried without Group Memberships 

To begin, users can be queried without any customization. Paging logic from the group aggregation can be reused, as GitLab only returns 100 users per page. While the parent API call produces the list of users, it does not include group memberships per user. 

Milestone 2: Match Top-Tier Memberships with Access Levels

I added an attribute to the user account schema called “groups” to store a list of groups a user has. Next, I added a child HTTP Operation that calls GET /users/{id}/memberships to query the groups each user is a member of. Access level per group is returned as part of this data.  

In the child HTTP Operation, I implemented a Web Services After Operation rule to concatenate the group ID and access levels for each API response. This allowed the data returned to match the naming customizations of the group entitlements, and therefore allow the groups to populate under the user accounts. However, this API call only returns direct memberships and excludes subgroups. 

Final Milestone: Match All Membership Tiers with Access Levels 

To show all group members, and inherited memberships, one must use the endpoint GET /groups/{id}/members/all. Without the /all at the end of the URL, only direct memberships will be shown 

First, a map is built from the response of this data, storing each user ID as a key and a list of group memberships per user as values. Our client did not need to differentiate between direct and inherited memberships, but if that was required, a separate map could be built to store subgroup data in isolation. 

After the map is built, for each 100 users returned by the original API call, their user ID is referenced in the map as a key, and the “groups” attribute is populated with their list of groups IDs concatenated with the access level. For instance, maintainer access to group ID 3223 would appear in the list as 3223-40. This algorithm successfully met all client requirements. 

Additional Operations

After completing the user and group aggregations, all of the GitLab data necessary to stage certifications was pulled into ISC. Since auditing access types with certifications was the goal of our client, we did not expand the implementation further. Other IAM account lifecycle use cases could have been incorporated into the GitLab application onboarding, including Remove Entitlement, Delete Account and Disable Account functionalities. HTTP Operations could also have been configured to automate certification remediations. While most of these expansions address automation of tasks involving manual work, the next expansion option addresses a security concern when relying solely on group memberships for access governance.

Choosing to import repository access, referred to in GitLab as projects, as part of the entitlements could prevent a case where a user is missing from a group but can still access a repository. A user can have access to a repository directly via project access, rather than through group memberships. Since a group can have multiple projects within it, one may prefer direct project membership over group membership for access governing. However, depending on the structure of group memberships, pulling in direct project access in addition to group memberships may reveal users who should be in groups but are instead incorrectly utilizing direct project access. 

Conclusion

Once the implementation efforts concluded, documented my experiences onboarding GitLab on-premise as an ISC application for other developers to use as a resource. In addition to the implementation delivered, I wanted to address use cases that could be built upon to meet a variety of IAM needs. 

For more guidance on this implementation, or other application onboarding needs, contact us so we can help SailPoint Identity Security Cloud work better for your environment!