Published on: June 18, 2025

6 min read

Automating role-based access control (RBAC) at scale

This guide details setting up GitLab + Keycloak + OIDC for RBAC, covering planning, Docker configuration, and automated access governance for DevSecOps.

Security starts with structure. Building a scalable and secure development platform begins with getting the fundamentals right — especially role-based access control (RBAC).

To help our customers scale effectively, we developed the RBAC Accelerator — a modular, outcome-driven enablement program that supports large organizations in defining, enforcing, and scaling access policies across GitLab.

This foundation enables broader transformation. For example, the Secure SDLC Accelerator, built on top of the RBAC Accelerator, empowers customers to integrate compliance, security, and DevSecOps best practices into their workflows.

GitLab customer Lely, a major Dutch manufacturer of agricultural machines and robots, used this approach to migrate to GitLab Dedicated. Lely automated user provisioning via Azure AD using OpenID Connect (OIDC), enforced least-privilege policies, and created a scalable, reusable access model to support their future development initiatives.

In this guide, we’ll take you through a hands-on implementation example of GitLab + Keycloak + OIDC, covering everything from running the setup in a Docker environment to automating role mapping, designing a scalable group hierarchy, and aligning GitLab access controls with organizational structure and compliance goals.

This is a local demo setup intended for proof-of-concept purposes only.

Whether you’re just starting out or optimizing at scale, this modular foundation ensures you’re not just securing access — you’re enabling everything that comes next.

Getting started with access control planning

Before implementing any tooling, it’s essential to understand your access landscape.

Consider:

  • What GitLab resources need protection (projects, groups, environments)?
  • Who are your personas (Developers, Maintainers, Guests, etc.)?
  • What organizational units (departments, cost centers) should govern access?
  • How does your IdP structure (Keycloak) define users and roles?

Use this stage to draft your:

  • Access control matrix
  • GitLab group hierarchy (team- or product-based)
  • Least privilege policy assumptions

Sample group hierarchy

graph TD Root["Root (Root Group)"] FirmwareTeam["Firmware-Team"] FirmwareDevelopers["Developers (GitLab Developer Role)"] FirmwareMaintainers["Maintainers (GitLab Maintainer Role)"] FirmwareReporters["Reporters (GitLab Reporter Role)"] HardwareTeam["Hardware-Team"] HardwareDevelopers["Developers"] SoftwareTeam["Software-Team"] SoftwareDevelopers["Developers"] SoftwareMaintainers["Maintainers"] SoftwareReporters["Reporters"] Enterprise --> FirmwareTeam Enterprise --> HardwareTeam Enterprise --> SoftwareTeam FirmwareTeam --> FirmwareDevelopers FirmwareTeam --> FirmwareMaintainers FirmwareTeam --> FirmwareReporters HardwareTeam --> HardwareDevelopers SoftwareTeam --> SoftwareDevelopers SoftwareTeam --> SoftwareMaintainers SoftwareTeam --> SoftwareReporters

Demo system setup: GitLab + Keycloak in a local Docker environment

Prerequisites

  • Docker, Docker Compose, OpenSSL
  • GitLab Version 17.7.3 and Keycloak Version 23.0.7 container images
  • Self-signed certificates

.env configuration

The demo setup is using the following GitLab and Keycloak versions, ports and secrets.

GitLab configuration

GITLAB_VERSION=17.7.3-ee.0
GITLAB_EXTERNAL_URL=http://localhost:8081
GITLAB_SSH_PORT=8222

Keycloak configuration

KEYCLOAK_VERSION=latest
KEYCLOAK_ADMIN=<your-admin-username>
KEYCLOAK_ADMIN_PASSWORD=<your-admin-password>
KEYCLOAK_HTTPS_PORT=8443
KEYCLOAK_CLIENT_SECRET=<your-client-secret>  # Get this from Keycloak after setup

Generate SSL certificates

To establish trust between GitLab and Keycloak, especially in a self-hosted Docker environment, we’ll need to generate self-signed SSL certificates. These certificates will enable encrypted HTTPS communication and ensure GitLab can securely talk to Keycloak during the OIDC authentication process.

For production environments, we recommend using certificates from a trusted Certificate Authority (CA), but for local testing and development, self-signed certificates are sufficient.

Follow these step-by-step instructions:

  1. Create a folder for the certificates.

mkdir -p certs

  1. Generate a self-signed certificate with OpenSSL.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout certs/tls.key \
  -out certs/tls.crt \
  -subj "/CN=keycloak" \
  -addext "subjectAltName=DNS:keycloak,DNS:localhost"
  1. Create a PKCS12 keystore for Keycloak.
openssl pkcs12 -export \
  -in certs/tls.crt \
  -inkey certs/tls.key \
  -out certs/keystore.p12 \
  -name keycloak \
  -password pass:password

Start the service using Docker compose

Now that we have our certificates, we can stand up our local GitLab + Keycloak environment using Docker Compose:

version: '3.8'
services:
  gitlab:
    image: gitlab/gitlab-ee:${GITLAB_VERSION}
    container_name: gitlab
    restart: unless-stopped
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url '${GITLAB_EXTERNAL_URL:-http://localhost:8081}'
        gitlab_rails['gitlab_shell_ssh_port'] = ${GITLAB_SSH_PORT:-8222}
        gitlab_rails['display_initial_root_password'] = true

        # OAuth Configuration
        gitlab_rails['omniauth_enabled'] = true
        gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']
        gitlab_rails['omniauth_block_auto_created_users'] = false
        gitlab_rails['omniauth_providers'] = [
            {
                'name' => 'openid_connect',
                'label' => 'Keycloak',
                'args' => {
                    'name' => 'openid_connect',
                    'scope' => ['openid', 'profile', 'email'],
                    'response_type' => 'code',
                    'issuer' => 'https://localhost:8443/realms/GitLab',
                    'client_auth_method' => 'query',
                    'discovery' => false,
                    'uid_field' => 'preferred_username',
                    'pkce' => true,
                    'client_options' => {
                        'identifier' => 'gitlab',
                        'secret' => '${KEYCLOAK_CLIENT_SECRET}',
                        'redirect_uri' => '${GITLAB_EXTERNAL_URL:-http://localhost:8081}/users/auth/openid_connect/callback',
                        'authorization_endpoint' => 'https://localhost:8443/realms/GitLab/protocol/openid-connect/auth',
                        'token_endpoint' => 'https://keycloak:8443/realms/GitLab/protocol/openid-connect/token',
                        'userinfo_endpoint' => 'https://keycloak:8443/realms/GitLab/protocol/openid-connect/userinfo',
                        'jwks_uri' => 'https://keycloak:8443/realms/GitLab/protocol/openid-connect/certs'
                    }
                }
            }
        ]
    volumes:
      - gl-config:/etc/gitlab
      - gl-data:/var/opt/gitlab
      - ./certs/tls.crt:/etc/gitlab/trusted-certs/keycloak.crt
    ports:
      - '${GITLAB_EXTERNAL_PORT:-8081}:8081'
      - '${GITLAB_SSH_PORT:-8222}:22'
    shm_size: '256m'

  keycloak:
    image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}
    container_name: keycloak-server
    restart: unless-stopped
    command: [
      "start-dev",
      "--import-realm",
      "--https-port=${KEYCLOAK_HTTPS_PORT}",
      "--https-key-store-file=/etc/x509/https/keystore.p12",
      "--https-key-store-password=password"
    ]
    volumes:
      - ./data:/opt/keycloak/data/import
      - ./certs:/etc/x509/https
    environment:
      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
    ports:
      - "${KEYCLOAK_HTTPS_PORT}:8443"

volumes:
  gl-config:
  gl-data:

Run the docker-compose up -d command and your GitLab + Keycloak environment will be up in minutes.

docker-compose up -d

Keycloak realm configuration

Your Keycloak realm is automatically configured on startup as it's defined in the docker-compose file.

The realm configuration will include:

  • Pre-configured GitLab client
  • Default client secret

You can access Keycloak admin console at https://localhost:8443 with:

  • Username: admin
  • Password: from your .env file
  • To verify the setup:
    • Log into Keycloak admin console
    • Select the GitLab realm
    • Check Clients > gitlab

Verify the client configuration matches your environment.

To showcase the automated RBAC mechanism, you will need to follow these steps:

  • Map realm roles to GitLab roles
  • Create group structure with mapping roles, matching the Group, Sub-group, Project pattern in GitLab.

Before provisioning your first users to the user groups, it’s recommended to log into your GitLab instance to retrieve your instance root password:

  1. Access GitLab at http://localhost:8081.

  2. Get the root password:

docker exec gitlab grep 'Password:' `/etc/gitlab/initial_root_password`

  1. Log in as root with the retrieved password.

Putting it all together

To demonstrate the power of this integrated RBAC model, start by walking through a real-world user journey — from identity to access.

Begin in Keycloak by showcasing a user assigned to specific realm roles (e.g., developer, maintainer) and groups (e.g., /engineering/platform). These roles have been mapped to GitLab access levels via OIDC claims, while group affiliations align with GitLab’s structured hierarchy of root groups, sub-groups, and projects.

Upon login through GitLab’s SSO Keycloak endpoint, the user is automatically provisioned into the correct group and assigned the appropriate role — with no manual intervention.

Within GitLab, you can see that the user can interact with the assigned project: For example, a developer might push code and open a merge request, but not merge to protected branches — validating the least-privilege model.

Finally, you can showcase access across multiple teams or products that are managed centrally in Keycloak, yet enforced precisely in GitLab through group sync and permissions inheritance. This demo illustrates not just role assignment, but how GitLab and Keycloak together deliver real-time, automated access governance at scale — ready for secure, compliant, enterprise-grade software development.

Why GitLab?

GitLab’s comprehensive, intelligent DevSecOps platform is the ideal foundation for secure, scalable access management. With native OIDC support, granular role enforcement, SCIM-based user provisioning, and built-in audit logging, GitLab allows organizations to centralize control without compromising agility. Its flexible group hierarchy mirrors enterprise structure, making it easy to manage access across teams.

Integrating with identity providers like Keycloak automates onboarding, ensures least-privilege access, and creates a seamless identity-to-permission pipeline that supports regulatory and security goals. As a core component of GitLab’s security capabilities, RBAC ties directly into CI/CD, policy enforcement, and vulnerability management workflows.

Summary

RBAC is just the beginning. With GitLab and Keycloak, you’re not just securing access — you’re enabling structured, automated governance that scales. As you expand into policy enforcement, Secure SDLC, and DevSecOps automation, this foundation becomes a launchpad for sustainable, enterprise-grade software delivery.

Get started with RBAC in GitLab today with a free, 60-day trial of GitLab Ultimate. Sign up today!

We want to hear from you

Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum.

50%+ of the Fortune 100 trust GitLab

Start shipping better software faster

See what your team can do with the intelligent

DevSecOps platform.