[{"data":1,"prerenderedAt":1989},["ShallowReactive",2],{"/blog/automating-role-based-access-control-rbac-at-scale":3,"navigation-en-us":1180,"banner-en-us":1607,"footer-en-us":1617,"blog-post-authors-en-us-James Wormwell|Paul Meresanu|Kees Valkhof":1862,"blog-related-posts-en-us-automating-role-based-access-control-rbac-at-scale":1901,"blog-promotions-en-us":1926,"next-steps-en-us":1979},{"id":4,"title":5,"authors":6,"body":10,"category":1165,"date":1166,"description":1167,"extension":1168,"externalUrl":1169,"faq":1169,"featured":115,"heroImage":1170,"meta":1171,"navigation":115,"path":1172,"seo":1173,"slug":1175,"stem":1176,"tags":1177,"template":1178,"updatedDate":1169,"__hash__":1179},"blogPosts/en-us/blog/automating-role-based-access-control-rbac-at-scale.md","Automating role-based access control (RBAC) at scale",[7,8,9],"James Wormwell","Paul Meresanu","Kees Valkhof",{"type":11,"value":12,"toc":1152},"minimark",[13,17,20,23,39,48,51,54,59,62,65,81,84,95,98,271,275,280,291,295,298,303,355,359,447,451,454,457,460,466,471,476,554,559,625,629,632,951,958,966,970,977,980,988,995,1029,1032,1035,1043,1046,1058,1095,1100,1104,1107,1110,1113,1116,1119,1123,1126,1129,1133,1136,1148],[14,15,16],"p",{},"Security starts with structure. Building a scalable and secure development platform begins with getting the fundamentals right — especially role-based access control (RBAC).",[14,18,19],{},"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.",[14,21,22],{},"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.",[14,24,25,26,32,33,38],{},"GitLab customer ",[27,28,31],"a",{"href":29,"rel":30},"https://www.lelyna.com/us/",[],"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 ",[27,34,37],{"href":35,"rel":36},"https://about.gitlab.com/blog/the-ultimate-guide-to-least-privilege-access-with-gitlab/",[],"least-privilege policies",", and created a scalable, reusable access model to support their future development initiatives.",[14,40,41,42,47],{},"In this guide, we’ll take you through a hands-on implementation example of GitLab + ",[27,43,46],{"href":44,"rel":45},"https://www.keycloak.org/",[],"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.",[14,49,50],{},"This is a local demo setup intended for proof-of-concept purposes only.",[14,52,53],{},"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.",[55,56,58],"h2",{"id":57},"getting-started-with-access-control-planning","Getting started with access control planning",[14,60,61],{},"Before implementing any tooling, it’s essential to understand your access landscape.",[14,63,64],{},"Consider:",[66,67,68,72,75,78],"ul",{},[69,70,71],"li",{},"What GitLab resources need protection (projects, groups, environments)?",[69,73,74],{},"Who are your personas (Developers, Maintainers, Guests, etc.)?",[69,76,77],{},"What organizational units (departments, cost centers) should govern access?",[69,79,80],{},"How does your IdP structure (Keycloak) define users and roles?",[14,82,83],{},"Use this stage to draft your:",[66,85,86,89,92],{},[69,87,88],{},"Access control matrix",[69,90,91],{},"GitLab group hierarchy (team- or product-based)",[69,93,94],{},"Least privilege policy assumptions",[14,96,97],{},"Sample group hierarchy",[99,100,105],"pre",{"className":101,"code":102,"language":103,"meta":104,"style":104},"language-mermaid shiki shiki-themes github-light","\ngraph TD\n    Root[\"Root (Root Group)\"]\n    FirmwareTeam[\"Firmware-Team\"]\n    FirmwareDevelopers[\"Developers (GitLab Developer Role)\"]\n    FirmwareMaintainers[\"Maintainers (GitLab Maintainer Role)\"]\n    FirmwareReporters[\"Reporters (GitLab Reporter Role)\"]\n    HardwareTeam[\"Hardware-Team\"]\n    HardwareDevelopers[\"Developers\"]\n    SoftwareTeam[\"Software-Team\"]\n    SoftwareDevelopers[\"Developers\"]\n    SoftwareMaintainers[\"Maintainers\"]\n    SoftwareReporters[\"Reporters\"]\n    \n    Enterprise --> FirmwareTeam\n    Enterprise --> HardwareTeam\n    Enterprise --> SoftwareTeam\n    \n    FirmwareTeam --> FirmwareDevelopers\n    FirmwareTeam --> FirmwareMaintainers\n    FirmwareTeam --> FirmwareReporters\n    \n    HardwareTeam --> HardwareDevelopers\n    \n    SoftwareTeam --> SoftwareDevelopers\n    SoftwareTeam --> SoftwareMaintainers\n    SoftwareTeam --> SoftwareReporters\n","mermaid","",[106,107,108,117,124,130,136,142,148,154,160,166,172,178,184,190,196,202,208,214,219,225,231,237,242,248,253,259,265],"code",{"__ignoreMap":104},[109,110,113],"span",{"class":111,"line":112},"line",1,[109,114,116],{"emptyLinePlaceholder":115},true,"\n",[109,118,120],{"class":111,"line":119},2,[109,121,123],{"class":122},"sgsFI","graph TD\n",[109,125,127],{"class":111,"line":126},3,[109,128,129],{"class":122},"    Root[\"Root (Root Group)\"]\n",[109,131,133],{"class":111,"line":132},4,[109,134,135],{"class":122},"    FirmwareTeam[\"Firmware-Team\"]\n",[109,137,139],{"class":111,"line":138},5,[109,140,141],{"class":122},"    FirmwareDevelopers[\"Developers (GitLab Developer Role)\"]\n",[109,143,145],{"class":111,"line":144},6,[109,146,147],{"class":122},"    FirmwareMaintainers[\"Maintainers (GitLab Maintainer Role)\"]\n",[109,149,151],{"class":111,"line":150},7,[109,152,153],{"class":122},"    FirmwareReporters[\"Reporters (GitLab Reporter Role)\"]\n",[109,155,157],{"class":111,"line":156},8,[109,158,159],{"class":122},"    HardwareTeam[\"Hardware-Team\"]\n",[109,161,163],{"class":111,"line":162},9,[109,164,165],{"class":122},"    HardwareDevelopers[\"Developers\"]\n",[109,167,169],{"class":111,"line":168},10,[109,170,171],{"class":122},"    SoftwareTeam[\"Software-Team\"]\n",[109,173,175],{"class":111,"line":174},11,[109,176,177],{"class":122},"    SoftwareDevelopers[\"Developers\"]\n",[109,179,181],{"class":111,"line":180},12,[109,182,183],{"class":122},"    SoftwareMaintainers[\"Maintainers\"]\n",[109,185,187],{"class":111,"line":186},13,[109,188,189],{"class":122},"    SoftwareReporters[\"Reporters\"]\n",[109,191,193],{"class":111,"line":192},14,[109,194,195],{"class":122},"    \n",[109,197,199],{"class":111,"line":198},15,[109,200,201],{"class":122},"    Enterprise --> FirmwareTeam\n",[109,203,205],{"class":111,"line":204},16,[109,206,207],{"class":122},"    Enterprise --> HardwareTeam\n",[109,209,211],{"class":111,"line":210},17,[109,212,213],{"class":122},"    Enterprise --> SoftwareTeam\n",[109,215,217],{"class":111,"line":216},18,[109,218,195],{"class":122},[109,220,222],{"class":111,"line":221},19,[109,223,224],{"class":122},"    FirmwareTeam --> FirmwareDevelopers\n",[109,226,228],{"class":111,"line":227},20,[109,229,230],{"class":122},"    FirmwareTeam --> FirmwareMaintainers\n",[109,232,234],{"class":111,"line":233},21,[109,235,236],{"class":122},"    FirmwareTeam --> FirmwareReporters\n",[109,238,240],{"class":111,"line":239},22,[109,241,195],{"class":122},[109,243,245],{"class":111,"line":244},23,[109,246,247],{"class":122},"    HardwareTeam --> HardwareDevelopers\n",[109,249,251],{"class":111,"line":250},24,[109,252,195],{"class":122},[109,254,256],{"class":111,"line":255},25,[109,257,258],{"class":122},"    SoftwareTeam --> SoftwareDevelopers\n",[109,260,262],{"class":111,"line":261},26,[109,263,264],{"class":122},"    SoftwareTeam --> SoftwareMaintainers\n",[109,266,268],{"class":111,"line":267},27,[109,269,270],{"class":122},"    SoftwareTeam --> SoftwareReporters\n",[55,272,274],{"id":273},"demo-system-setup-gitlab-keycloak-in-a-local-docker-environment","Demo system setup: GitLab + Keycloak in a local Docker environment",[276,277,279],"h3",{"id":278},"prerequisites","Prerequisites",[66,281,282,285,288],{},[69,283,284],{},"Docker, Docker Compose, OpenSSL",[69,286,287],{},"GitLab Version 17.7.3 and Keycloak Version 23.0.7 container images",[69,289,290],{},"Self-signed certificates",[276,292,294],{"id":293},"env-configuration",".env configuration",[14,296,297],{},"The demo setup is using the following GitLab and Keycloak versions, ports and secrets.",[299,300,302],"h4",{"id":301},"gitlab-configuration","GitLab configuration",[99,304,308],{"className":305,"code":306,"language":307,"meta":104,"style":104},"language-bash shiki shiki-themes github-light","\nGITLAB_VERSION=17.7.3-ee.0\n\nGITLAB_EXTERNAL_URL=http://localhost:8081\n\nGITLAB_SSH_PORT=8222\n\n","bash",[106,309,310,314,327,331,341,345],{"__ignoreMap":104},[109,311,312],{"class":111,"line":112},[109,313,116],{"emptyLinePlaceholder":115},[109,315,316,319,323],{"class":111,"line":119},[109,317,318],{"class":122},"GITLAB_VERSION",[109,320,322],{"class":321},"sD7c4","=",[109,324,326],{"class":325},"sYBdl","17.7.3-ee.0\n",[109,328,329],{"class":111,"line":126},[109,330,116],{"emptyLinePlaceholder":115},[109,332,333,336,338],{"class":111,"line":132},[109,334,335],{"class":122},"GITLAB_EXTERNAL_URL",[109,337,322],{"class":321},[109,339,340],{"class":325},"http://localhost:8081\n",[109,342,343],{"class":111,"line":138},[109,344,116],{"emptyLinePlaceholder":115},[109,346,347,350,352],{"class":111,"line":144},[109,348,349],{"class":122},"GITLAB_SSH_PORT",[109,351,322],{"class":321},[109,353,354],{"class":325},"8222\n",[299,356,358],{"id":357},"keycloak-configuration","Keycloak configuration",[99,360,362],{"className":305,"code":361,"language":307,"meta":104,"style":104},"\nKEYCLOAK_VERSION=latest\n\nKEYCLOAK_ADMIN=\u003Cyour-admin-username>\n\nKEYCLOAK_ADMIN_PASSWORD=\u003Cyour-admin-password>\n\nKEYCLOAK_HTTPS_PORT=8443\n\nKEYCLOAK_CLIENT_SECRET=\u003Cyour-client-secret>  # Get this from Keycloak after setup\n\n",[106,363,364,368,378,382,396,400,412,416,426,430],{"__ignoreMap":104},[109,365,366],{"class":111,"line":112},[109,367,116],{"emptyLinePlaceholder":115},[109,369,370,373,375],{"class":111,"line":119},[109,371,372],{"class":122},"KEYCLOAK_VERSION",[109,374,322],{"class":321},[109,376,377],{"class":325},"latest\n",[109,379,380],{"class":111,"line":126},[109,381,116],{"emptyLinePlaceholder":115},[109,383,384,387,390,393],{"class":111,"line":132},[109,385,386],{"class":122},"KEYCLOAK_ADMIN",[109,388,389],{"class":321},"=\u003C",[109,391,392],{"class":325},"your-admin-username",[109,394,395],{"class":321},">\n",[109,397,398],{"class":111,"line":138},[109,399,116],{"emptyLinePlaceholder":115},[109,401,402,405,407,410],{"class":111,"line":144},[109,403,404],{"class":122},"KEYCLOAK_ADMIN_PASSWORD",[109,406,389],{"class":321},[109,408,409],{"class":325},"your-admin-password",[109,411,395],{"class":321},[109,413,414],{"class":111,"line":150},[109,415,116],{"emptyLinePlaceholder":115},[109,417,418,421,423],{"class":111,"line":156},[109,419,420],{"class":122},"KEYCLOAK_HTTPS_PORT",[109,422,322],{"class":321},[109,424,425],{"class":325},"8443\n",[109,427,428],{"class":111,"line":162},[109,429,116],{"emptyLinePlaceholder":115},[109,431,432,435,437,440,443],{"class":111,"line":168},[109,433,434],{"class":122},"KEYCLOAK_CLIENT_SECRET",[109,436,389],{"class":321},[109,438,439],{"class":325},"your-client-secret",[109,441,442],{"class":321},">",[109,444,446],{"class":445},"sAwPA","  # Get this from Keycloak after setup\n",[55,448,450],{"id":449},"generate-ssl-certificates","Generate SSL certificates",[14,452,453],{},"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.",[14,455,456],{},"For production environments, we recommend using certificates from a trusted Certificate Authority (CA), but for local testing and development, self-signed certificates are sufficient.",[14,458,459],{},"Follow these step-by-step instructions:",[461,462,463],"ol",{},[69,464,465],{},"Create a folder for the certificates.",[14,467,468],{},[106,469,470],{},"shell mkdir -p certs ",[461,472,473],{"start":119},[69,474,475],{},"Generate a self-signed certificate with OpenSSL.",[99,477,479],{"className":305,"code":478,"language":307,"meta":104,"style":104},"\nopenssl req -x509 -nodes -days 365 -newkey rsa:2048 \\\n  -keyout certs/tls.key \\\n  -out certs/tls.crt \\\n  -subj \"/CN=keycloak\" \\\n  -addext \"subjectAltName=DNS:keycloak,DNS:localhost\"\n",[106,480,481,485,516,526,536,546],{"__ignoreMap":104},[109,482,483],{"class":111,"line":112},[109,484,116],{"emptyLinePlaceholder":115},[109,486,487,491,494,498,501,504,507,510,513],{"class":111,"line":119},[109,488,490],{"class":489},"s7eDp","openssl",[109,492,493],{"class":325}," req",[109,495,497],{"class":496},"sYu0t"," -x509",[109,499,500],{"class":496}," -nodes",[109,502,503],{"class":496}," -days",[109,505,506],{"class":496}," 365",[109,508,509],{"class":496}," -newkey",[109,511,512],{"class":325}," rsa:2048",[109,514,515],{"class":496}," \\\n",[109,517,518,521,524],{"class":111,"line":126},[109,519,520],{"class":496},"  -keyout",[109,522,523],{"class":325}," certs/tls.key",[109,525,515],{"class":496},[109,527,528,531,534],{"class":111,"line":132},[109,529,530],{"class":496},"  -out",[109,532,533],{"class":325}," certs/tls.crt",[109,535,515],{"class":496},[109,537,538,541,544],{"class":111,"line":138},[109,539,540],{"class":496},"  -subj",[109,542,543],{"class":325}," \"/CN=keycloak\"",[109,545,515],{"class":496},[109,547,548,551],{"class":111,"line":144},[109,549,550],{"class":496},"  -addext",[109,552,553],{"class":325}," \"subjectAltName=DNS:keycloak,DNS:localhost\"\n",[461,555,556],{"start":126},[69,557,558],{},"Create a PKCS12 keystore for Keycloak.",[99,560,562],{"className":305,"code":561,"language":307,"meta":104,"style":104},"\nopenssl pkcs12 -export \\\n  -in certs/tls.crt \\\n  -inkey certs/tls.key \\\n  -out certs/keystore.p12 \\\n  -name keycloak \\\n  -password pass:password\n",[106,563,564,568,580,589,598,607,617],{"__ignoreMap":104},[109,565,566],{"class":111,"line":112},[109,567,116],{"emptyLinePlaceholder":115},[109,569,570,572,575,578],{"class":111,"line":119},[109,571,490],{"class":489},[109,573,574],{"class":325}," pkcs12",[109,576,577],{"class":496}," -export",[109,579,515],{"class":496},[109,581,582,585,587],{"class":111,"line":126},[109,583,584],{"class":496},"  -in",[109,586,533],{"class":325},[109,588,515],{"class":496},[109,590,591,594,596],{"class":111,"line":132},[109,592,593],{"class":496},"  -inkey",[109,595,523],{"class":325},[109,597,515],{"class":496},[109,599,600,602,605],{"class":111,"line":138},[109,601,530],{"class":496},[109,603,604],{"class":325}," certs/keystore.p12",[109,606,515],{"class":496},[109,608,609,612,615],{"class":111,"line":144},[109,610,611],{"class":496},"  -name",[109,613,614],{"class":325}," keycloak",[109,616,515],{"class":496},[109,618,619,622],{"class":111,"line":150},[109,620,621],{"class":496},"  -password",[109,623,624],{"class":325}," pass:password\n",[55,626,628],{"id":627},"start-the-service-using-docker-compose","Start the service using Docker compose",[14,630,631],{},"Now that we have our certificates, we can stand up our local GitLab + Keycloak environment using Docker Compose:",[99,633,637],{"className":634,"code":635,"language":636,"meta":104,"style":104},"language-yaml shiki shiki-themes github-light","\nversion: '3.8' services:\n  gitlab:\n    image: gitlab/gitlab-ee:${GITLAB_VERSION}\n    container_name: gitlab restart: unless-stopped environment:\n      GITLAB_OMNIBUS_CONFIG: | external_url '${GITLAB_EXTERNAL_URL:-http://localhost:8081}' gitlab_rails['gitlab_shell_ssh_port'] = ${GITLAB_SSH_PORT:-8222}\n        gitlab_rails['display_initial_root_password'] = true\n\n        # 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'] = [\n            { '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'\n                    }\n                }\n            }\n        ] volumes:\n      - gl-config:/etc/gitlab\n      - gl-data:/var/opt/gitlab\n      - ./certs/tls.crt:/etc/gitlab/trusted-certs/keycloak.crt\n    ports:\n      - '${GITLAB_EXTERNAL_PORT:-8081}:8081'\n      - '${GITLAB_SSH_PORT:-8222}:22'\n    shm_size: '256m' keycloak:\n    image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}\n    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\"\n    ] volumes:\n      - ./data:/opt/keycloak/data/import\n      - ./certs:/etc/x509/https\n    environment:\n      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}\n      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}\n    ports:\n      - \"${KEYCLOAK_HTTPS_PORT}:8443\"\n\nvolumes:\n  gl-config:\n  gl-data:\n","yaml",[106,638,639,643,661,668,678,695,709,714,718,723,728,733,738,743,748,756,763,770,777,784,791,805,814,855,865,872,879,886,897,908,915,923,928,935,943],{"__ignoreMap":104},[109,640,641],{"class":111,"line":112},[109,642,116],{"emptyLinePlaceholder":115},[109,644,645,649,652,655,658],{"class":111,"line":119},[109,646,648],{"class":647},"shJU0","version",[109,650,651],{"class":122},": ",[109,653,654],{"class":325},"'3.8'",[109,656,657],{"class":647}," services",[109,659,660],{"class":122},":\n",[109,662,663,666],{"class":111,"line":126},[109,664,665],{"class":647},"  gitlab",[109,667,660],{"class":122},[109,669,670,673,675],{"class":111,"line":132},[109,671,672],{"class":647},"    image",[109,674,651],{"class":122},[109,676,677],{"class":325},"gitlab/gitlab-ee:${GITLAB_VERSION}\n",[109,679,680,683,685,688,690,693],{"class":111,"line":138},[109,681,682],{"class":647},"    container_name",[109,684,651],{"class":122},[109,686,687],{"class":647},"gitlab restart",[109,689,651],{"class":122},[109,691,692],{"class":647},"unless-stopped environment",[109,694,660],{"class":122},[109,696,697,700,702,705],{"class":111,"line":144},[109,698,699],{"class":647},"      GITLAB_OMNIBUS_CONFIG",[109,701,651],{"class":122},[109,703,704],{"class":321},"|",[109,706,708],{"class":707},"sB1qb"," external_url '${GITLAB_EXTERNAL_URL:-http://localhost:8081}' gitlab_rails['gitlab_shell_ssh_port'] = ${GITLAB_SSH_PORT:-8222}\n",[109,710,711],{"class":111,"line":150},[109,712,713],{"class":325},"        gitlab_rails['display_initial_root_password'] = true\n",[109,715,716],{"class":111,"line":156},[109,717,116],{"emptyLinePlaceholder":115},[109,719,720],{"class":111,"line":162},[109,721,722],{"class":325},"        # 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'] = [\n",[109,724,725],{"class":111,"line":168},[109,726,727],{"class":325},"            { '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'\n",[109,729,730],{"class":111,"line":174},[109,731,732],{"class":325},"                    }\n",[109,734,735],{"class":111,"line":180},[109,736,737],{"class":325},"                }\n",[109,739,740],{"class":111,"line":186},[109,741,742],{"class":325},"            }\n",[109,744,745],{"class":111,"line":192},[109,746,747],{"class":325},"        ] volumes:\n",[109,749,750,753],{"class":111,"line":198},[109,751,752],{"class":122},"      - ",[109,754,755],{"class":325},"gl-config:/etc/gitlab\n",[109,757,758,760],{"class":111,"line":204},[109,759,752],{"class":122},[109,761,762],{"class":325},"gl-data:/var/opt/gitlab\n",[109,764,765,767],{"class":111,"line":210},[109,766,752],{"class":122},[109,768,769],{"class":325},"./certs/tls.crt:/etc/gitlab/trusted-certs/keycloak.crt\n",[109,771,772,775],{"class":111,"line":216},[109,773,774],{"class":647},"    ports",[109,776,660],{"class":122},[109,778,779,781],{"class":111,"line":221},[109,780,752],{"class":122},[109,782,783],{"class":325},"'${GITLAB_EXTERNAL_PORT:-8081}:8081'\n",[109,785,786,788],{"class":111,"line":227},[109,787,752],{"class":122},[109,789,790],{"class":325},"'${GITLAB_SSH_PORT:-8222}:22'\n",[109,792,793,796,798,801,803],{"class":111,"line":233},[109,794,795],{"class":647},"    shm_size",[109,797,651],{"class":122},[109,799,800],{"class":325},"'256m'",[109,802,614],{"class":647},[109,804,660],{"class":122},[109,806,807,809,811],{"class":111,"line":239},[109,808,672],{"class":647},[109,810,651],{"class":122},[109,812,813],{"class":325},"quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}\n",[109,815,816,818,820,823,825,828,831,834,837,840,842,845,847,850,852],{"class":111,"line":244},[109,817,682],{"class":647},[109,819,651],{"class":122},[109,821,822],{"class":647},"keycloak-server restart",[109,824,651],{"class":122},[109,826,827],{"class":647},"unless-stopped command",[109,829,830],{"class":122},": [ ",[109,832,833],{"class":325},"\"start-dev\"",[109,835,836],{"class":122},", ",[109,838,839],{"class":325},"\"--import-realm\"",[109,841,836],{"class":122},[109,843,844],{"class":325},"\"--https-port=${KEYCLOAK_HTTPS_PORT}\"",[109,846,836],{"class":122},[109,848,849],{"class":325},"\"--https-key-store-file=/etc/x509/https/keystore.p12\"",[109,851,836],{"class":122},[109,853,854],{"class":325},"\"--https-key-store-password=password\"\n",[109,856,857,860,863],{"class":111,"line":250},[109,858,859],{"class":122},"    ] ",[109,861,862],{"class":647},"volumes",[109,864,660],{"class":122},[109,866,867,869],{"class":111,"line":255},[109,868,752],{"class":122},[109,870,871],{"class":325},"./data:/opt/keycloak/data/import\n",[109,873,874,876],{"class":111,"line":261},[109,875,752],{"class":122},[109,877,878],{"class":325},"./certs:/etc/x509/https\n",[109,880,881,884],{"class":111,"line":267},[109,882,883],{"class":647},"    environment",[109,885,660],{"class":122},[109,887,889,892,894],{"class":111,"line":888},28,[109,890,891],{"class":647},"      KEYCLOAK_ADMIN",[109,893,651],{"class":122},[109,895,896],{"class":325},"${KEYCLOAK_ADMIN}\n",[109,898,900,903,905],{"class":111,"line":899},29,[109,901,902],{"class":647},"      KEYCLOAK_ADMIN_PASSWORD",[109,904,651],{"class":122},[109,906,907],{"class":325},"${KEYCLOAK_ADMIN_PASSWORD}\n",[109,909,911,913],{"class":111,"line":910},30,[109,912,774],{"class":647},[109,914,660],{"class":122},[109,916,918,920],{"class":111,"line":917},31,[109,919,752],{"class":122},[109,921,922],{"class":325},"\"${KEYCLOAK_HTTPS_PORT}:8443\"\n",[109,924,926],{"class":111,"line":925},32,[109,927,116],{"emptyLinePlaceholder":115},[109,929,931,933],{"class":111,"line":930},33,[109,932,862],{"class":647},[109,934,660],{"class":122},[109,936,938,941],{"class":111,"line":937},34,[109,939,940],{"class":647},"  gl-config",[109,942,660],{"class":122},[109,944,946,949],{"class":111,"line":945},35,[109,947,948],{"class":647},"  gl-data",[109,950,660],{"class":122},[14,952,953,954,957],{},"Run the ",[106,955,956],{},"docker-compose up -d"," command and your GitLab + Keycloak environment will be up in minutes.",[99,959,964],{"className":960,"code":962,"language":963,"meta":104},[961],"language-text","\ndocker-compose up -d\n\n","text",[106,965,962],{"__ignoreMap":104},[55,967,969],{"id":968},"keycloak-realm-configuration","Keycloak realm configuration",[14,971,972,973,976],{},"Your Keycloak realm is automatically configured on startup as it's defined in the ",[106,974,975],{},"docker-compose"," file.",[14,978,979],{},"The realm configuration will include:",[66,981,982,985],{},[69,983,984],{},"Pre-configured GitLab client",[69,986,987],{},"Default client secret",[14,989,990,991,994],{},"You can access Keycloak admin console at ",[106,992,993],{},"https://localhost:8443"," with:",[66,996,997,1000,1007],{},[69,998,999],{},"Username: admin",[69,1001,1002,1003,1006],{},"Password: from your ",[106,1004,1005],{},".env"," file",[69,1008,1009,1010],{},"To verify the setup:",[66,1011,1012,1015,1023],{},[69,1013,1014],{},"Log into Keycloak admin console",[69,1016,1017,1018,1022],{},"Select the ",[1019,1020,1021],"strong",{},"GitLab"," realm",[69,1024,1025,1026],{},"Check ",[1019,1027,1028],{},"Clients > gitlab",[14,1030,1031],{},"Verify the client configuration matches your environment.",[14,1033,1034],{},"To showcase the automated RBAC mechanism, you will need to follow these steps:",[66,1036,1037,1040],{},[69,1038,1039],{},"Map realm roles to GitLab roles",[69,1041,1042],{},"Create group structure with mapping roles, matching the Group, Sub-group, Project pattern in GitLab.",[14,1044,1045],{},"Before provisioning your first users to the user groups, it’s recommended to log into your GitLab instance to retrieve your instance root password:",[461,1047,1048,1055],{},[69,1049,1050,1051,1054],{},"Access GitLab at ",[106,1052,1053],{},"http://localhost:8081",".",[69,1056,1057],{},"Get the root password:",[99,1059,1063],{"className":1060,"code":1061,"language":1062,"meta":104,"style":104},"language-shell shiki shiki-themes github-light","\ndocker exec gitlab grep 'Password:' `/etc/gitlab/initial_root_password`\n\n","shell",[106,1064,1065,1069],{"__ignoreMap":104},[109,1066,1067],{"class":111,"line":112},[109,1068,116],{"emptyLinePlaceholder":115},[109,1070,1071,1074,1077,1080,1083,1086,1089,1092],{"class":111,"line":119},[109,1072,1073],{"class":489},"docker",[109,1075,1076],{"class":325}," exec",[109,1078,1079],{"class":325}," gitlab",[109,1081,1082],{"class":325}," grep",[109,1084,1085],{"class":325}," 'Password:'",[109,1087,1088],{"class":325}," `",[109,1090,1091],{"class":489},"/etc/gitlab/initial_root_password",[109,1093,1094],{"class":325},"`\n",[461,1096,1097],{"start":126},[69,1098,1099],{},"Log in as root with the retrieved password.",[55,1101,1103],{"id":1102},"putting-it-all-together","Putting it all together",[14,1105,1106],{},"To demonstrate the power of this integrated RBAC model, start by walking through a real-world user journey — from identity to access.",[14,1108,1109],{},"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.",[14,1111,1112],{},"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.",[14,1114,1115],{},"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.",[14,1117,1118],{},"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.",[55,1120,1122],{"id":1121},"why-gitlab","Why GitLab?",[14,1124,1125],{},"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.",[14,1127,1128],{},"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.",[55,1130,1132],{"id":1131},"summary","Summary",[14,1134,1135],{},"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.",[1137,1138,1139],"blockquote",{},[14,1140,1141,1142,1147],{},"Get started with RBAC in GitLab today with a free trial of GitLab Ultimate. ",[27,1143,1146],{"href":1144,"rel":1145},"https://about.gitlab.com/free-trial/",[],"Sign up today","!",[1149,1150,1151],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sB1qb, html code.shiki .sB1qb{--shiki-default:#B31D28;--shiki-default-font-style:italic}",{"title":104,"searchDepth":119,"depth":119,"links":1153},[1154,1155,1159,1160,1161,1162,1163,1164],{"id":57,"depth":119,"text":58},{"id":273,"depth":119,"text":274,"children":1156},[1157,1158],{"id":278,"depth":126,"text":279},{"id":293,"depth":126,"text":294},{"id":449,"depth":119,"text":450},{"id":627,"depth":119,"text":628},{"id":968,"depth":119,"text":969},{"id":1102,"depth":119,"text":1103},{"id":1121,"depth":119,"text":1122},{"id":1131,"depth":119,"text":1132},"security","2025-06-20","This guide details setting up GitLab + Keycloak + OIDC for RBAC, covering planning, Docker configuration, and automated access governance for DevSecOps.","md",null,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659561/Blog/Hero%20Images/securitycheck.png",{},"/en-us/blog/automating-role-based-access-control-rbac-at-scale",{"noIndex":1174,"title":5,"description":1167},false,"automating-role-based-access-control-rbac-at-scale","en-us/blog/automating-role-based-access-control-rbac-at-scale",[1165],"BlogPost","8ctOWbxWEXjlFDRi2L7sSELmHhFBZhbYhEb34ghc6N4",{"logo":1181,"freeTrial":1186,"sales":1191,"login":1196,"items":1201,"search":1528,"minimal":1558,"duo":1577,"switchNav":1586,"pricingDeployment":1597},{"config":1182},{"href":1183,"dataGaName":1184,"dataGaLocation":1185},"/","gitlab logo","header",{"text":1187,"config":1188},"Get free trial",{"href":1189,"dataGaName":1190,"dataGaLocation":1185},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1192,"config":1193},"Request a demo",{"href":1194,"dataGaName":1195,"dataGaLocation":1185},"/sales/?contact-topic=request-demo","sales",{"text":1197,"config":1198},"Sign in",{"href":1199,"dataGaName":1200,"dataGaLocation":1185},"https://gitlab.com/users/sign_in/","sign in",[1202,1231,1331,1336,1450,1506],{"text":1203,"config":1204,"menu":1206},"Platform",{"dataNavLevelOne":1205},"platform",{"type":1207,"columns":1208},"cards",[1209,1215,1223],{"title":1203,"description":1210,"link":1211},"The intelligent orchestration platform for DevSecOps",{"text":1212,"config":1213},"Explore our Platform",{"href":1214,"dataGaName":1205,"dataGaLocation":1185},"/platform/",{"title":1216,"description":1217,"link":1218},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1219,"config":1220},"Meet GitLab Duo",{"href":1221,"dataGaName":1222,"dataGaLocation":1185},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1224,"description":1225,"link":1226},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1227,"config":1228},"Learn more",{"href":1229,"dataGaName":1230,"dataGaLocation":1185},"/why-gitlab/","why gitlab",{"text":1232,"left":115,"config":1233,"menu":1235},"Product",{"dataNavLevelOne":1234},"solutions",{"type":1236,"link":1237,"columns":1241,"feature":1310},"lists",{"text":1238,"config":1239},"View all Solutions",{"href":1240,"dataGaName":1234,"dataGaLocation":1185},"/solutions/",[1242,1266,1289],{"title":1243,"description":1244,"link":1245,"items":1250},"Automation","CI/CD and automation to accelerate deployment",{"config":1246},{"icon":1247,"href":1248,"dataGaName":1249,"dataGaLocation":1185},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1251,1255,1258,1262],{"text":1252,"config":1253},"CI/CD",{"href":1254,"dataGaLocation":1185,"dataGaName":1252},"/solutions/continuous-integration/",{"text":1216,"config":1256},{"href":1221,"dataGaLocation":1185,"dataGaName":1257},"gitlab duo agent platform - product menu",{"text":1259,"config":1260},"Source Code Management",{"href":1261,"dataGaLocation":1185,"dataGaName":1259},"/solutions/source-code-management/",{"text":1263,"config":1264},"Automated Software Delivery",{"href":1248,"dataGaLocation":1185,"dataGaName":1265},"Automated software delivery",{"title":1267,"description":1268,"link":1269,"items":1274},"Security","Deliver code faster without compromising security",{"config":1270},{"href":1271,"dataGaName":1272,"dataGaLocation":1185,"icon":1273},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1275,1279,1284],{"text":1276,"config":1277},"Application Security Testing",{"href":1271,"dataGaName":1278,"dataGaLocation":1185},"Application security testing",{"text":1280,"config":1281},"Software Supply Chain Security",{"href":1282,"dataGaLocation":1185,"dataGaName":1283},"/solutions/supply-chain/","Software supply chain security",{"text":1285,"config":1286},"Software Compliance",{"href":1287,"dataGaName":1288,"dataGaLocation":1185},"/solutions/software-compliance/","software compliance",{"title":1290,"link":1291,"items":1296},"Measurement",{"config":1292},{"icon":1293,"href":1294,"dataGaName":1295,"dataGaLocation":1185},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1297,1301,1305],{"text":1298,"config":1299},"Visibility & Measurement",{"href":1294,"dataGaLocation":1185,"dataGaName":1300},"Visibility and Measurement",{"text":1302,"config":1303},"Value Stream Management",{"href":1304,"dataGaLocation":1185,"dataGaName":1302},"/solutions/value-stream-management/",{"text":1306,"config":1307},"Analytics & Insights",{"href":1308,"dataGaLocation":1185,"dataGaName":1309},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1311,"type":1236,"items":1312},"GitLab for",[1313,1319,1325],{"text":1314,"config":1315},"Enterprise",{"icon":1316,"href":1317,"dataGaLocation":1185,"dataGaName":1318},"Building","/enterprise/","enterprise",{"text":1320,"config":1321},"Small Business",{"icon":1322,"href":1323,"dataGaLocation":1185,"dataGaName":1324},"Work","/small-business/","small business",{"text":1326,"config":1327},"Public Sector",{"icon":1328,"href":1329,"dataGaLocation":1185,"dataGaName":1330},"Organization","/solutions/public-sector/","public sector",{"text":1332,"config":1333},"Pricing",{"href":1334,"dataGaName":1335,"dataGaLocation":1185,"dataNavLevelOne":1335},"/pricing/","pricing",{"text":1337,"config":1338,"menu":1340},"Resources",{"dataNavLevelOne":1339},"resources",{"type":1236,"link":1341,"columns":1345,"feature":1439},{"text":1342,"config":1343},"View all resources",{"href":1344,"dataGaName":1339,"dataGaLocation":1185},"/resources/",[1346,1379,1406],{"title":1347,"items":1348},"Getting started",[1349,1354,1359,1364,1369,1374],{"text":1350,"config":1351},"Install",{"href":1352,"dataGaName":1353,"dataGaLocation":1185},"/install/","install",{"text":1355,"config":1356},"Quick start guides",{"href":1357,"dataGaName":1358,"dataGaLocation":1185},"/get-started/","quick setup checklists",{"text":1360,"config":1361},"Learn",{"href":1362,"dataGaLocation":1185,"dataGaName":1363},"https://university.gitlab.com/","learn",{"text":1365,"config":1366},"Product documentation",{"href":1367,"dataGaName":1368,"dataGaLocation":1185},"https://docs.gitlab.com/","product documentation",{"text":1370,"config":1371},"Best practice videos",{"href":1372,"dataGaName":1373,"dataGaLocation":1185},"/getting-started-videos/","best practice videos",{"text":1375,"config":1376},"Integrations",{"href":1377,"dataGaName":1378,"dataGaLocation":1185},"/integrations/","integrations",{"title":1380,"items":1381},"Discover",[1382,1387,1392,1397,1401],{"text":1383,"config":1384},"Customer success stories",{"href":1385,"dataGaName":1386,"dataGaLocation":1185},"/customers/","customer success stories",{"text":1388,"config":1389},"Blog",{"href":1390,"dataGaName":1391,"dataGaLocation":1185},"/blog/","blog",{"text":1393,"config":1394},"Demo Hub",{"href":1395,"dataGaName":1396,"dataGaLocation":1185},"/demo-hub/","demo hub",{"text":1398,"config":1399},"The Source",{"href":1400,"dataGaName":1391,"dataGaLocation":1185},"/the-source/",{"text":1402,"config":1403},"Remote",{"href":1404,"dataGaName":1405,"dataGaLocation":1185},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1407,"items":1408},"Connect",[1409,1414,1419,1424,1429,1434],{"text":1410,"config":1411},"GitLab Services",{"href":1412,"dataGaName":1413,"dataGaLocation":1185},"/services/","services",{"text":1415,"config":1416},"Contribute",{"href":1417,"dataGaName":1418,"dataGaLocation":1185},"https://contributors.gitlab.com","contribute",{"text":1420,"config":1421},"Community",{"href":1422,"dataGaName":1423,"dataGaLocation":1185},"/community/","community",{"text":1425,"config":1426},"Forum",{"href":1427,"dataGaName":1428,"dataGaLocation":1185},"https://forum.gitlab.com/","forum",{"text":1430,"config":1431},"Events",{"href":1432,"dataGaName":1433,"dataGaLocation":1185},"/events/","events",{"text":1435,"config":1436},"Partners",{"href":1437,"dataGaName":1438,"dataGaLocation":1185},"/partners/","partners",{"config":1440,"title":1443,"text":1444,"link":1445},{"background":1441,"textColor":1442},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1446,"config":1447},"Read the latest",{"href":1448,"dataGaName":1449,"dataGaLocation":1185},"/whats-new/","whats new",{"text":1451,"config":1452,"menu":1454},"Company",{"dataNavLevelOne":1453},"company",{"type":1236,"columns":1455},[1456],{"items":1457},[1458,1463,1469,1471,1476,1481,1486,1491,1496,1501],{"text":1459,"config":1460},"About",{"href":1461,"dataGaName":1462,"dataGaLocation":1185},"/company/","about",{"text":1464,"config":1465,"footerGa":1468},"Jobs",{"href":1466,"dataGaName":1467,"dataGaLocation":1185},"/jobs/","jobs",{"dataGaName":1467},{"text":1430,"config":1470},{"href":1432,"dataGaName":1433,"dataGaLocation":1185},{"text":1472,"config":1473},"Leadership",{"href":1474,"dataGaName":1475,"dataGaLocation":1185},"/company/team/e-group/","leadership",{"text":1477,"config":1478},"Handbook",{"href":1479,"dataGaName":1480,"dataGaLocation":1185},"https://handbook.gitlab.com/","handbook",{"text":1482,"config":1483},"Investor relations",{"href":1484,"dataGaName":1485,"dataGaLocation":1185},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1487,"config":1488},"Trust Center",{"href":1489,"dataGaName":1490,"dataGaLocation":1185},"/security/","trust center",{"text":1492,"config":1493},"AI Transparency Center",{"href":1494,"dataGaName":1495,"dataGaLocation":1185},"/ai-transparency-center/","ai transparency center",{"text":1497,"config":1498},"Newsletter",{"href":1499,"dataGaName":1500,"dataGaLocation":1185},"/company/contact/#contact-forms","newsletter",{"text":1502,"config":1503},"Press",{"href":1504,"dataGaName":1505,"dataGaLocation":1185},"/press/","press",{"text":1507,"config":1508,"menu":1509},"Contact us",{"dataNavLevelOne":1453},{"type":1236,"columns":1510},[1511],{"items":1512},[1513,1518,1523],{"text":1514,"config":1515},"Talk to sales",{"href":1516,"dataGaName":1517,"dataGaLocation":1185},"/sales/","talk to sales",{"text":1519,"config":1520},"Support portal",{"href":1521,"dataGaName":1522,"dataGaLocation":1185},"https://support.gitlab.com/hc/en-us","support portal",{"text":1524,"config":1525},"Customer portal",{"href":1526,"dataGaName":1527,"dataGaLocation":1185},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1529,"login":1530,"suggestions":1537},"Close",{"text":1531,"link":1532},"To search repositories and projects, login to",{"text":1533,"config":1534},"gitlab.com",{"href":1199,"dataGaName":1535,"dataGaLocation":1536},"search login","search",{"text":1538,"default":1539},"Suggestions",[1540,1542,1546,1548,1552,1556],{"text":1216,"config":1541},{"href":1221,"dataGaName":1216,"dataGaLocation":1536},{"text":1543,"config":1544},"Code Suggestions (AI)",{"href":1545,"dataGaName":1543,"dataGaLocation":1536},"/solutions/code-suggestions/",{"text":1252,"config":1547},{"href":1254,"dataGaName":1252,"dataGaLocation":1536},{"text":1549,"config":1550},"GitLab on AWS",{"href":1551,"dataGaName":1549,"dataGaLocation":1536},"/partners/technology-partners/aws/",{"text":1553,"config":1554},"GitLab on Google Cloud",{"href":1555,"dataGaName":1553,"dataGaLocation":1536},"/partners/technology-partners/google-cloud-platform/",{"text":1122,"config":1557},{"href":1229,"dataGaName":1122,"dataGaLocation":1536},{"freeTrial":1559,"mobileIcon":1564,"desktopIcon":1569,"secondaryButton":1572},{"text":1560,"config":1561},"Start free trial",{"href":1562,"dataGaName":1190,"dataGaLocation":1563},"https://gitlab.com/-/trials/new/","nav",{"altText":1565,"config":1566},"Gitlab Icon",{"src":1567,"dataGaName":1568,"dataGaLocation":1563},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1565,"config":1570},{"src":1571,"dataGaName":1568,"dataGaLocation":1563},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1573,"config":1574},"Get Started",{"href":1575,"dataGaName":1576,"dataGaLocation":1563},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1578,"mobileIcon":1582,"desktopIcon":1584},{"text":1579,"config":1580},"Learn more about GitLab Duo",{"href":1221,"dataGaName":1581,"dataGaLocation":1563},"gitlab duo",{"altText":1565,"config":1583},{"src":1567,"dataGaName":1568,"dataGaLocation":1563},{"altText":1565,"config":1585},{"src":1571,"dataGaName":1568,"dataGaLocation":1563},{"button":1587,"mobileIcon":1592,"desktopIcon":1594},{"text":1588,"config":1589},"/switch",{"href":1590,"dataGaName":1591,"dataGaLocation":1563},"#contact","switch",{"altText":1565,"config":1593},{"src":1567,"dataGaName":1568,"dataGaLocation":1563},{"altText":1565,"config":1595},{"src":1596,"dataGaName":1568,"dataGaLocation":1563},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1598,"mobileIcon":1603,"desktopIcon":1605},{"text":1599,"config":1600},"Back to pricing",{"href":1334,"dataGaName":1601,"dataGaLocation":1563,"icon":1602},"back to pricing","GoBack",{"altText":1565,"config":1604},{"src":1567,"dataGaName":1568,"dataGaLocation":1563},{"altText":1565,"config":1606},{"src":1571,"dataGaName":1568,"dataGaLocation":1563},{"title":1608,"titleMobile":1609,"button":1610,"config":1615},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1227,"config":1611},{"href":1612,"dataGaName":1613,"dataGaLocation":1614},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1616,"disabled":1174},"release",{"data":1618},{"text":1619,"source":1620,"edit":1626,"contribute":1631,"config":1636,"items":1641,"minimal":1851},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1621,"config":1622},"View page source",{"href":1623,"dataGaName":1624,"dataGaLocation":1625},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1627,"config":1628},"Edit this page",{"href":1629,"dataGaName":1630,"dataGaLocation":1625},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1632,"config":1633},"Please contribute",{"href":1634,"dataGaName":1635,"dataGaLocation":1625},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1637,"facebook":1638,"youtube":1639,"linkedin":1640},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1642,1689,1743,1787,1819],{"title":1332,"links":1643,"subMenu":1658},[1644,1648,1653],{"text":1645,"config":1646},"View plans",{"href":1334,"dataGaName":1647,"dataGaLocation":1625},"view plans",{"text":1649,"config":1650},"Why Premium?",{"href":1651,"dataGaName":1652,"dataGaLocation":1625},"/pricing/premium/","why premium",{"text":1654,"config":1655},"Why Ultimate?",{"href":1656,"dataGaName":1657,"dataGaLocation":1625},"/pricing/ultimate/","why ultimate",[1659],{"title":1660,"links":1661},"Contact Us",[1662,1665,1667,1669,1674,1679,1684],{"text":1663,"config":1664},"Contact sales",{"href":1516,"dataGaName":1195,"dataGaLocation":1625},{"text":1519,"config":1666},{"href":1521,"dataGaName":1522,"dataGaLocation":1625},{"text":1524,"config":1668},{"href":1526,"dataGaName":1527,"dataGaLocation":1625},{"text":1670,"config":1671},"Status",{"href":1672,"dataGaName":1673,"dataGaLocation":1625},"https://status.gitlab.com/","status",{"text":1675,"config":1676},"Terms of use",{"href":1677,"dataGaName":1678,"dataGaLocation":1625},"/terms/","terms of use",{"text":1680,"config":1681},"Privacy statement",{"href":1682,"dataGaName":1683,"dataGaLocation":1625},"/privacy/","privacy statement",{"text":1685,"config":1686},"Cookie preferences",{"dataGaName":1687,"dataGaLocation":1625,"id":1688,"isOneTrustButton":115},"cookie preferences","ot-sdk-btn",{"title":1232,"links":1690,"subMenu":1699},[1691,1695],{"text":1692,"config":1693},"DevSecOps platform",{"href":1214,"dataGaName":1694,"dataGaLocation":1625},"devsecops platform",{"text":1696,"config":1697},"AI-Assisted Development",{"href":1221,"dataGaName":1698,"dataGaLocation":1625},"ai-assisted development",[1700],{"title":1701,"links":1702},"Topics",[1703,1708,1713,1718,1723,1728,1733,1738],{"text":1704,"config":1705},"CICD",{"href":1706,"dataGaName":1707,"dataGaLocation":1625},"/topics/ci-cd/","cicd",{"text":1709,"config":1710},"GitOps",{"href":1711,"dataGaName":1712,"dataGaLocation":1625},"/topics/gitops/","gitops",{"text":1714,"config":1715},"DevOps",{"href":1716,"dataGaName":1717,"dataGaLocation":1625},"/topics/devops/","devops",{"text":1719,"config":1720},"Version Control",{"href":1721,"dataGaName":1722,"dataGaLocation":1625},"/topics/version-control/","version control",{"text":1724,"config":1725},"DevSecOps",{"href":1726,"dataGaName":1727,"dataGaLocation":1625},"/topics/devsecops/","devsecops",{"text":1729,"config":1730},"Cloud Native",{"href":1731,"dataGaName":1732,"dataGaLocation":1625},"/topics/cloud-native/","cloud native",{"text":1734,"config":1735},"AI for Coding",{"href":1736,"dataGaName":1737,"dataGaLocation":1625},"/topics/devops/ai-for-coding/","ai for coding",{"text":1739,"config":1740},"Agentic AI",{"href":1741,"dataGaName":1742,"dataGaLocation":1625},"/topics/agentic-ai/","agentic ai",{"title":1744,"links":1745},"Solutions",[1746,1748,1750,1755,1759,1762,1766,1769,1771,1774,1777,1782],{"text":1276,"config":1747},{"href":1271,"dataGaName":1276,"dataGaLocation":1625},{"text":1265,"config":1749},{"href":1248,"dataGaName":1249,"dataGaLocation":1625},{"text":1751,"config":1752},"Agile development",{"href":1753,"dataGaName":1754,"dataGaLocation":1625},"/solutions/agile-delivery/","agile delivery",{"text":1756,"config":1757},"SCM",{"href":1261,"dataGaName":1758,"dataGaLocation":1625},"source code management",{"text":1704,"config":1760},{"href":1254,"dataGaName":1761,"dataGaLocation":1625},"continuous integration & delivery",{"text":1763,"config":1764},"Value stream management",{"href":1304,"dataGaName":1765,"dataGaLocation":1625},"value stream management",{"text":1709,"config":1767},{"href":1768,"dataGaName":1712,"dataGaLocation":1625},"/solutions/gitops/",{"text":1314,"config":1770},{"href":1317,"dataGaName":1318,"dataGaLocation":1625},{"text":1772,"config":1773},"Small business",{"href":1323,"dataGaName":1324,"dataGaLocation":1625},{"text":1775,"config":1776},"Public sector",{"href":1329,"dataGaName":1330,"dataGaLocation":1625},{"text":1778,"config":1779},"Education",{"href":1780,"dataGaName":1781,"dataGaLocation":1625},"/solutions/education/","education",{"text":1783,"config":1784},"Financial services",{"href":1785,"dataGaName":1786,"dataGaLocation":1625},"/solutions/finance/","financial services",{"title":1337,"links":1788},[1789,1791,1793,1795,1798,1800,1803,1805,1807,1809,1811,1813,1815,1817],{"text":1350,"config":1790},{"href":1352,"dataGaName":1353,"dataGaLocation":1625},{"text":1355,"config":1792},{"href":1357,"dataGaName":1358,"dataGaLocation":1625},{"text":1360,"config":1794},{"href":1362,"dataGaName":1363,"dataGaLocation":1625},{"text":1365,"config":1796},{"href":1367,"dataGaName":1797,"dataGaLocation":1625},"docs",{"text":1388,"config":1799},{"href":1390,"dataGaName":1391,"dataGaLocation":1625},{"text":1801,"config":1802},"What's new",{"href":1448,"dataGaName":1449,"dataGaLocation":1625},{"text":1383,"config":1804},{"href":1385,"dataGaName":1386,"dataGaLocation":1625},{"text":1402,"config":1806},{"href":1404,"dataGaName":1405,"dataGaLocation":1625},{"text":1410,"config":1808},{"href":1412,"dataGaName":1413,"dataGaLocation":1625},{"text":1415,"config":1810},{"href":1417,"dataGaName":1418,"dataGaLocation":1625},{"text":1420,"config":1812},{"href":1422,"dataGaName":1423,"dataGaLocation":1625},{"text":1425,"config":1814},{"href":1427,"dataGaName":1428,"dataGaLocation":1625},{"text":1430,"config":1816},{"href":1432,"dataGaName":1433,"dataGaLocation":1625},{"text":1435,"config":1818},{"href":1437,"dataGaName":1438,"dataGaLocation":1625},{"title":1451,"links":1820},[1821,1823,1825,1827,1829,1831,1835,1840,1842,1844,1846],{"text":1459,"config":1822},{"href":1461,"dataGaName":1453,"dataGaLocation":1625},{"text":1464,"config":1824},{"href":1466,"dataGaName":1467,"dataGaLocation":1625},{"text":1472,"config":1826},{"href":1474,"dataGaName":1475,"dataGaLocation":1625},{"text":1477,"config":1828},{"href":1479,"dataGaName":1480,"dataGaLocation":1625},{"text":1482,"config":1830},{"href":1484,"dataGaName":1485,"dataGaLocation":1625},{"text":1832,"config":1833},"Sustainability",{"href":1834,"dataGaName":1832,"dataGaLocation":1625},"/sustainability/",{"text":1836,"config":1837},"Diversity, inclusion and belonging (DIB)",{"href":1838,"dataGaName":1839,"dataGaLocation":1625},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1487,"config":1841},{"href":1489,"dataGaName":1490,"dataGaLocation":1625},{"text":1497,"config":1843},{"href":1499,"dataGaName":1500,"dataGaLocation":1625},{"text":1502,"config":1845},{"href":1504,"dataGaName":1505,"dataGaLocation":1625},{"text":1847,"config":1848},"Modern Slavery Transparency Statement",{"href":1849,"dataGaName":1850,"dataGaLocation":1625},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1852},[1853,1856,1859],{"text":1854,"config":1855},"Terms",{"href":1677,"dataGaName":1678,"dataGaLocation":1625},{"text":1857,"config":1858},"Cookies",{"dataGaName":1687,"dataGaLocation":1625,"id":1688,"isOneTrustButton":115},{"text":1860,"config":1861},"Privacy",{"href":1682,"dataGaName":1683,"dataGaLocation":1625},[1863,1877,1889],{"id":1864,"title":7,"body":1169,"config":1865,"content":1867,"description":1169,"extension":1871,"meta":1872,"navigation":115,"path":1873,"seo":1874,"stem":1875,"__hash__":1876},"blogAuthors/en-us/blog/authors/james-wormwell.yml",{"template":1866},"BlogAuthor",{"name":7,"config":1868},{"headshot":1869,"ctfId":1870},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659474/Blog/Author%20Headshots/james_wormwell_headshot.png","CPPijHb0Op5C5aVcvsOEf","yml",{},"/en-us/blog/authors/james-wormwell",{},"en-us/blog/authors/james-wormwell","n6G4XENUWxgqOdCgfG0ECu0Uqj7qOS9zr3Rl8ouF49M",{"id":1878,"title":8,"body":1169,"config":1879,"content":1881,"description":1169,"extension":1871,"meta":1884,"navigation":115,"path":1885,"seo":1886,"stem":1887,"__hash__":1888},"blogAuthors/en-us/blog/authors/paul-meresanu.yml",{"template":1866,"gitlabHandle":1880},"pmeresanu",{"name":8,"role":104,"config":1882},{"headshot":1883},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1750267141/qpw5ayteg0sewyh7s8xi.png",{},"/en-us/blog/authors/paul-meresanu",{},"en-us/blog/authors/paul-meresanu","S41feQ9U81y4EVDx5pEECPqpIEiKTCDLBOmNwjLyE1E",{"id":1890,"title":9,"body":1169,"config":1891,"content":1892,"description":1169,"extension":1871,"meta":1896,"navigation":115,"path":1897,"seo":1898,"stem":1899,"__hash__":1900},"blogAuthors/en-us/blog/authors/kees-valkhof.yml",{"template":1866},{"name":9,"role":1893,"config":1894},"Configuration manager at Lely",{"headshot":1895},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1750331281/xojwtvpk5pif84wlahx1.jpg",{},"/en-us/blog/authors/kees-valkhof",{},"en-us/blog/authors/kees-valkhof","CUxOh-7QjB6WokGlmdFbfR45LKv0C3d1tHGfi-KIveg",[1902,1910,1918],{"title":1903,"description":1904,"heroImage":1905,"category":1165,"date":1906,"authors":1907,"slug":1909,"externalUrl":1169},"How GitLab tracks vulnerabilities through refactors and reformatting","Learn how GitLab's improved Scope+Offset fingerprinting keeps vulnerability tracking stable across comments, blank lines, and reformatting.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1759320418/xjmqcozxzt4frx0hori3.png","2026-08-12",[1908],"Julian Thome","improved-scope-offset-fingerprinting",{"title":1911,"description":1912,"heroImage":1905,"category":1165,"date":1913,"authors":1914,"slug":1917,"externalUrl":1169},"GitLab Secrets Manager adds ESO, Terraform, API support","Simplify credential management across your stack. GitLab Secrets Manager provides secure retrieval in Kubernetes, Terraform, and external workflows.","2026-08-06",[1915,1916],"Erick Bajao","Joe Randazzo","gitlab-secrets-manager-add-eso-terraform-api-support",{"title":1919,"description":1920,"heroImage":1921,"category":1165,"date":1922,"authors":1923,"slug":1925,"externalUrl":1169},"Secure every commit to production with Claude and GitLab","Claude Security catches vulnerabilities inside a coding session. GitLab picks up from there, scanning, enforcing policy, and producing audit evidence for the software lifecycle. ","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756122536/akivvcnafog9c4dhhzkp.png","2026-08-03",[1924],"Alisa Ho","claude-security-and-gitlab",{"promotions":1927},[1928,1942,1954,1965],{"id":1929,"categories":1930,"header":1932,"text":1933,"button":1934,"image":1939},"ai-modernization",[1931],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1935,"config":1936},"Get your AI maturity score",{"href":1937,"dataGaName":1938,"dataGaLocation":1391},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1940},{"src":1941},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1943,"categories":1944,"header":1946,"text":1933,"button":1947,"image":1951},"devops-modernization",[1945,1727],"product","Are you just managing tools or shipping innovation?",{"text":1948,"config":1949},"Get your DevOps maturity score",{"href":1950,"dataGaName":1938,"dataGaLocation":1391},"/assessments/devops-modernization-assessment/",{"config":1952},{"src":1953},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1955,"categories":1956,"header":1957,"text":1933,"button":1958,"image":1962},"security-modernization",[1165],"Are you trading speed for security?",{"text":1959,"config":1960},"Get your security maturity score",{"href":1961,"dataGaName":1938,"dataGaLocation":1391},"/assessments/security-modernization-assessment/",{"config":1963},{"src":1964},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1966,"paths":1967,"header":1970,"text":1971,"button":1972,"image":1977},"github-azure-migration",[1968,1969],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1973,"config":1974},"See how GitLab compares to GitHub",{"href":1975,"dataGaName":1976,"dataGaLocation":1391},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1978},{"src":1953},{"header":1980,"blurb":1981,"button":1982,"secondaryButton":1987},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1983,"config":1984},"Get your free trial",{"href":1985,"dataGaName":1190,"dataGaLocation":1986},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1663,"config":1988},{"href":1516,"dataGaName":1195,"dataGaLocation":1986},1786803730673]