[{"data":1,"prerenderedAt":1202},["ShallowReactive",2],{"/blog/enable-secure-sudo-access-for-gitlab-remote-development-workspaces":3,"navigation-en-us":417,"banner-en-us":845,"footer-en-us":855,"blog-post-authors-en-us-Vishal Tak":1099,"blog-related-posts-en-us-enable-secure-sudo-access-for-gitlab-remote-development-workspaces":1114,"blog-promotions-en-us":1139,"next-steps-en-us":1192},{"id":4,"title":5,"authors":6,"body":8,"category":394,"date":395,"description":396,"extension":397,"externalUrl":398,"faq":398,"featured":399,"heroImage":400,"meta":401,"navigation":399,"path":402,"seo":403,"slug":408,"stem":409,"tags":410,"template":415,"updatedDate":398,"__hash__":416},"blogPosts/en-us/blog/enable-secure-sudo-access-for-gitlab-remote-development-workspaces.md","Enable secure sudo access for GitLab Remote Development workspaces",[7],"Vishal Tak",{"type":9,"value":10,"toc":384},"minimark",[11,22,27,30,41,56,63,69,78,84,120,123,129,135,141,145,154,157,164,167,172,179,182,196,202,220,224,231,234,244,250,260,264,271,274,283,289,299,310,314,320,330,345,347,353,357,369,380],[12,13,14,15,21],"p",{},"A development environment often requires sudo permissions to install, configure, and use dependencies during runtime. GitLab now allows secure sudo access for ",[16,17,20],"a",{"href":18,"rel":19},"https://about.gitlab.com/blog/quick-start-guide-for-gitlab-workspaces/",[],"GitLab Remote Development workspaces",". This tutorial shows you how to enable GitLab workspace users to securely use sudo commands to perform common tasks.",[23,24,26],"h2",{"id":25},"the-challenge","The challenge",[12,28,29],{},"For the sake of this article, say your project is as simple as the below code.",[31,32,38],"pre",{"className":33,"code":35,"language":36,"meta":37},[34],"language-text","package main\n\nimport (\n    \"encoding/json\"\n    \"log/slog\"\n    \"net/http\"\n    \"os\"\n)\n\nfunc main() {\n    // Set up JSON logger\n    logFile, err := os.OpenFile(\"server.log\", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)\n    if err != nil {\n        panic(err)\n    }\n    defer logFile.Close()\n\n    jsonHandler := slog.NewJSONHandler(logFile, nil)\n    logger := slog.New(jsonHandler)\n    slog.SetDefault(logger)\n\n    // Define handlers\n    http.HandleFunc(\"/path1\", handleRequest)\n    http.HandleFunc(\"/path2\", handleRequest)\n\n    // Start server\n    slog.Info(\"Starting server on :3000\")\n    err = http.ListenAndServe(\":3000\", nil)\n    if err != nil {\n        slog.Error(\"Server failed to start\", \"error\", err)\n    }\n}\n\nfunc handleRequest(w http.ResponseWriter, r *http.Request) {\n    data := make(map[string]interface{})\n    for k, v := range r.Header {\n        data[k] = v\n    }\n\n    data[\"method\"] = r.Method\n    data[\"url\"] = r.URL.String()\n    data[\"remote_addr\"] = r.RemoteAddr\n\n    response, err := json.MarshalIndent(data, \"\", \"  \")\n    if err != nil {\n        slog.Error(\"Failed to marshal metadata\", \"error\", err)\n        http.Error(w, \"Internal Server Error\", http.StatusInternalServerError)\n        return\n    }\n\n    // Log the metadata\n    slog.Info(\"Request received\",\n        \"path\", r.URL.Path,\n        \"response\", string(response),\n    )\n\n    // Write response\n    w.Header().Set(\"Content-Type\", \"application/json\")\n    w.Write(response)\n}\n","text","",[39,40,35],"code",{"__ignoreMap":37},[12,42,43,44,47,48,51,52,55],{},"This code starts an HTTP server on port 3000, exposes two paths: ",[39,45,46],{},"path1"," and ",[39,49,50],{},"path2",". Each HTTP request received is logged to a file ",[39,53,54],{},"server.log",".",[12,57,58,59,62],{},"Let's run this code with ",[39,60,61],{},"go run main.go"," and generate some requests.",[31,64,67],{"className":65,"code":66,"language":36,"meta":37},[34],"i=1\nwhile [ \"$i\" -le 100 ]; do\n  echo \"Iteration $i\"\n\n  if [ $((random_number % 2)) -eq 0 ]; then\n    curl \"localhost:3000/path1\"\n  else\n    curl \"localhost:3000/path2\"\n  fi\n\n  i=$((i + 1))\ndone\n",[39,68,66],{"__ignoreMap":37},[12,70,71,72,77],{},"As you work on this application, you realize the need to analyze the logs to debug an issue. You look at the log file and it is long to parse with a simple glance. You remember there is a handy tool, ",[16,73,76],{"href":74,"rel":75},"https://jqlang.github.io/jq/",[],"jq",", which parses JSON data. But your workspace does not have it installed.",[12,79,80,81,83],{},"You want to install ",[39,82,76],{}," through the package manager for this workspace only.",[31,85,89],{"className":86,"code":87,"language":88,"meta":37,"style":37},"language-shell shiki shiki-themes github-light","sudo apt update\nsudo apt install jq\n","shell",[39,90,91,107],{"__ignoreMap":37},[92,93,96,100,104],"span",{"class":94,"line":95},"line",1,[92,97,99],{"class":98},"s7eDp","sudo",[92,101,103],{"class":102},"sYBdl"," apt",[92,105,106],{"class":102}," update\n",[92,108,110,112,114,117],{"class":94,"line":109},2,[92,111,99],{"class":98},[92,113,103],{"class":102},[92,115,116],{"class":102}," install",[92,118,119],{"class":102}," jq\n",[12,121,122],{},"The output is:",[31,124,127],{"className":125,"code":126,"language":36,"meta":37},[34],"sudo: The \"no new privileges\" flag is set, which prevents sudo from running as root.\nsudo: If sudo is running in a container, you may need to adjust the container configuration to disable the flag.\n",[39,128,126],{"__ignoreMap":37},[12,130,131,132,134],{},"This happens because GitLab workspaces explicitly disallows ",[39,133,99],{}," access to prevent privilege escalation on the Kubernetes host.",[12,136,137,138,140],{},"Now, there is a more secure way to run ",[39,139,99],{}," commands in a workspace.",[23,142,144],{"id":143},"how-sudo-access-works","How sudo access works",[12,146,147,148,153],{},"That is exactly what we have ",[16,149,152],{"href":150,"rel":151},"https://docs.gitlab.com/user/workspace/configuration/#configure-sudo-access-for-a-workspace",[],"unlocked"," in the 17.4 release of GitLab.",[12,155,156],{},"You can configure secure sudo access for workspaces using any of the following options:",[158,159,160],"ul",{},[161,162,163],"li",{},"Sysbox  - Kata Containers  - User namespaces",[12,165,166],{},"We will set up three GitLab agents for workspaces to demonstrate each option.",[168,169,171],"h3",{"id":170},"sysbox","Sysbox",[12,173,174,178],{},[16,175,171],{"href":176,"rel":177},"https://github.com/nestybox/sysbox",[]," is a container runtime that improves container isolation and enables containers to run the same workloads as virtual machines.",[12,180,181],{},"To configure sudo access for a workspace with Sysbox:",[183,184,185,193],"ol",{},[161,186,187,188,55],{},"In the Kubernetes cluster, ",[16,189,192],{"href":190,"rel":191},"https://github.com/nestybox/sysbox#installation",[],"install Sysbox",[161,194,195],{},"In the GitLab agent for workspaces, set the following config:",[31,197,200],{"className":198,"code":199,"language":36,"meta":37},[34],"remote_development:\n  enabled: true\n  dns_zone: \"sysbox-update.me.com\"\n  default_runtime_class: \"sysbox-runc\"\n  allow_privilege_escalation: true\n  annotations:\n    \"io.kubernetes.cri-o.userns-mode\": \"auto:size=65536\"\n",[39,201,199],{"__ignoreMap":37},[183,203,205],{"start":204},3,[161,206,207,208,213,214,219],{},"Add other settings in the agent config as per your requirements. ",[16,209,212],{"href":210,"rel":211},"https://docs.gitlab.com/user/workspace/gitlab_agent_configuration/#workspace-settings",[],"GitLab agent for workspaces settings"," for more information about individual settings.  4. Allow the agent to be used for workspaces in a group. See the ",[16,215,218],{"href":216,"rel":217},"https://docs.gitlab.com/user/workspace/gitlab_agent_configuration/#allow-a-cluster-agent-for-workspaces-in-a-group",[],"documentation"," for more information.  5. Update GitLab Workspaces Proxy to serve traffic for the domain used in the above agent configuration. See Tutorial: Set up the GitLab workspaces proxy for more information.",[168,221,223],{"id":222},"kata-containers","Kata Containers",[12,225,226,230],{},[16,227,223],{"href":228,"rel":229},"https://github.com/kata-containers/kata-containers",[]," is a standard implementation of lightweight virtual machines that perform like containers but provide the workload isolation and security of virtual machines.",[12,232,233],{},"To configure sudo access for a workspace with Kata Containers:",[183,235,236],{},[161,237,187,238,243],{},[16,239,242],{"href":240,"rel":241},"https://github.com/kata-containers/kata-containers/tree/main/docs/install",[],"install Kata Containers",".  2. In the GitLab agent for workspaces, set the following config:",[31,245,248],{"className":246,"code":247,"language":36,"meta":37},[34],"remote_development:\n  enabled: true\n  dns_zone: \"kata-update.me.com\"\n  default_runtime_class: \"kata-qemu\"\n  allow_privilege_escalation: true\n",[39,249,247],{"__ignoreMap":37},[183,251,252],{"start":204},[161,253,207,254,213,257,219],{},[16,255,212],{"href":210,"rel":256},[],[16,258,218],{"href":216,"rel":259},[],[168,261,263],{"id":262},"user-namespaces","User namespaces",[12,265,266,270],{},[16,267,263],{"href":268,"rel":269},"https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/",[]," isolate the user running inside the container from the user on the host.",[12,272,273],{},"To configure sudo access for a workspace with user namespaces:",[183,275,276],{},[161,277,187,278,243],{},[16,279,282],{"href":280,"rel":281},"https://kubernetes.io/blog/userns-beta/",[],"configure user namespaces",[31,284,287],{"className":285,"code":286,"language":36,"meta":37},[34],"remote_development:\n  enabled: true\n  dns_zone: \"userns-update.me.com\"\n  use_kubernetes_user_namespaces: true\n  allow_privilege_escalation: true\n",[39,288,286],{"__ignoreMap":37},[183,290,291],{"start":204},[161,292,207,293,213,296,219],{},[16,294,212],{"href":210,"rel":295},[],[16,297,218],{"href":216,"rel":298},[],[12,300,301,302,55],{},"Setting up a Kubernetes cluster with user namespaces configured is challenging since it is behind a beta feature gate in Kubernetes Version 1.31.0. This means it is not yet possible to configure such a cluster on the major cloud providers because they don't provide a mechanism to enable feature gates in their managed Kubernetes offering. Here is an example of ",[16,303,306,307],{"href":304,"rel":305},"https://gitlab.com/gitlab-org/gitlab/-/issues/468290#note_1959300036",[],"configuring a simple Kuberenetes cluster using ",[39,308,309],{},"kubeadm",[168,311,313],{"id":312},"create-a-workspace","Create a workspace",[12,315,316,317,319],{},"If you now create a workspace with these agents and try installing ",[39,318,76],{}," through a package manager, it should succeed!",[12,321,322,323,325,326,329],{},"You can analyze the logs using ",[39,324,76],{},". Say you wanted to inspect the log entries where the path is ",[39,327,328],{},"/path1",", you can run:",[31,331,333],{"className":86,"code":332,"language":88,"meta":37,"style":37},"jq 'select(.path == \"/path1\")' server.log\n",[39,334,335],{"__ignoreMap":37},[92,336,337,339,342],{"class":94,"line":95},[92,338,76],{"class":98},[92,340,341],{"class":102}," 'select(.path == \"/path1\")'",[92,343,344],{"class":102}," server.log\n",[12,346,122],{},[31,348,351],{"className":349,"code":350,"language":36,"meta":37},[34],"{\n  \"time\": \"2024-10-31T12:04:38.474806+05:30\",\n  \"level\": \"INFO\",\n  \"msg\": \"Request received\",\n  \"path\": \"/path1\",\n  \"response\": \"{\\n  \\\"Accept\\\": [\\n    \\\"*/*\\\"\\n  ],\\n  \\\"User-Agent\\\": [\\n    \\\"curl/8.7.1\\\"\\n  ],\\n  \\\"method\\\": \\\"GET\\\",\\n  \\\"remote_addr\\\": \\\"[::1]:61246\\\",\\n  \\\"url\\\": \\\"/path1\\\"\\n}\"\n}\n{\n  \"time\": \"2024-10-31T12:06:22.397453+05:30\",\n  \"level\": \"INFO\",\n  \"msg\": \"Request received\",\n  \"path\": \"/path1\",\n  \"response\": \"{\\n  \\\"Accept\\\": [\\n    \\\"*/*\\\"\\n  ],\\n  \\\"User-Agent\\\": [\\n    \\\"curl/8.7.1\\\"\\n  ],\\n  \\\"method\\\": \\\"GET\\\",\\n  \\\"remote_addr\\\": \\\"[::1]:61311\\\",\\n  \\\"url\\\": \\\"/path1\\\"\\n}\"\n}\n{\n  \"time\": \"2024-10-31T12:19:34.974354+05:30\",\n  \"level\": \"INFO\",\n  \"msg\": \"Request received\",\n  \"path\": \"/path1\",\n  \"response\": \"{\\n  \\\"Accept\\\": [\\n    \\\"*/*\\\"\\n  ],\\n  \\\"User-Agent\\\": [\\n    \\\"curl/8.7.1\\\"\\n  ],\\n  \\\"method\\\": \\\"GET\\\",\\n  \\\"remote_addr\\\": \\\"[::1]:61801\\\",\\n  \\\"url\\\": \\\"/path1\\\"\\n}\"\n}\n",[39,352,350],{"__ignoreMap":37},[23,354,356],{"id":355},"get-started-today","Get started today",[12,358,359,360,364,365,368],{},"Learn even more with our ",[16,361,363],{"href":150,"rel":362},[],"Configure sudo access for a workspace documentation",". See ",[16,366,212],{"href":210,"rel":367},[]," for details on individual settings.",[370,371,372],"blockquote",{},[12,373,374,375,379],{},"New to GitLab Remote Development? Here is a ",[16,376,378],{"href":18,"rel":377},[],"quickstart guide"," to get you up to speed.",[381,382,383],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}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);}",{"title":37,"searchDepth":109,"depth":109,"links":385},[386,387,393],{"id":25,"depth":109,"text":26},{"id":143,"depth":109,"text":144,"children":388},[389,390,391,392],{"id":170,"depth":204,"text":171},{"id":222,"depth":204,"text":223},{"id":262,"depth":204,"text":263},{"id":312,"depth":204,"text":313},{"id":355,"depth":109,"text":356},"security","2024-11-20","Learn how to allow support for sudo commands using Sysbox, Kata Containers, and user namespaces in this easy-to-follow tutorial.","md",null,true,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749675033/Blog/Hero%20Images/blog-image-template-1800x945.png",{},"/en-us/blog/enable-secure-sudo-access-for-gitlab-remote-development-workspaces",{"title":5,"description":396,"ogTitle":5,"ogDescription":396,"noIndex":404,"ogImage":400,"ogUrl":405,"ogSiteName":406,"ogType":407,"canonicalUrls":405},false,"https://about.gitlab.com/blog/enable-secure-sudo-access-for-gitlab-remote-development-workspaces","https://about.gitlab.com","article","enable-secure-sudo-access-for-gitlab-remote-development-workspaces","en-us/blog/enable-secure-sudo-access-for-gitlab-remote-development-workspaces",[394,411,412,413,414],"tutorial","remote work","DevSecOps platform","collaboration","BlogPost","niKPn_haYwViatmc3UzUrdzhh3qRfDPhRqF0g15S0ZY",{"logo":418,"freeTrial":423,"sales":428,"login":433,"items":438,"search":765,"minimal":796,"duo":815,"switchNav":824,"pricingDeployment":835},{"config":419},{"href":420,"dataGaName":421,"dataGaLocation":422},"/","gitlab logo","header",{"text":424,"config":425},"Get free trial",{"href":426,"dataGaName":427,"dataGaLocation":422},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":429,"config":430},"Request a demo",{"href":431,"dataGaName":432,"dataGaLocation":422},"/sales/?contact-topic=request-demo","sales",{"text":434,"config":435},"Sign in",{"href":436,"dataGaName":437,"dataGaLocation":422},"https://gitlab.com/users/sign_in/","sign in",[439,468,568,573,687,743],{"text":440,"config":441,"menu":443},"Platform",{"dataNavLevelOne":442},"platform",{"type":444,"columns":445},"cards",[446,452,460],{"title":440,"description":447,"link":448},"The intelligent orchestration platform for DevSecOps",{"text":449,"config":450},"Explore our Platform",{"href":451,"dataGaName":442,"dataGaLocation":422},"/platform/",{"title":453,"description":454,"link":455},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":456,"config":457},"Meet GitLab Duo",{"href":458,"dataGaName":459,"dataGaLocation":422},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":461,"description":462,"link":463},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":464,"config":465},"Learn more",{"href":466,"dataGaName":467,"dataGaLocation":422},"/why-gitlab/","why gitlab",{"text":469,"left":399,"config":470,"menu":472},"Product",{"dataNavLevelOne":471},"solutions",{"type":473,"link":474,"columns":478,"feature":547},"lists",{"text":475,"config":476},"View all Solutions",{"href":477,"dataGaName":471,"dataGaLocation":422},"/solutions/",[479,503,526],{"title":480,"description":481,"link":482,"items":487},"Automation","CI/CD and automation to accelerate deployment",{"config":483},{"icon":484,"href":485,"dataGaName":486,"dataGaLocation":422},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[488,492,495,499],{"text":489,"config":490},"CI/CD",{"href":491,"dataGaLocation":422,"dataGaName":489},"/solutions/continuous-integration/",{"text":453,"config":493},{"href":458,"dataGaLocation":422,"dataGaName":494},"gitlab duo agent platform - product menu",{"text":496,"config":497},"Source Code Management",{"href":498,"dataGaLocation":422,"dataGaName":496},"/solutions/source-code-management/",{"text":500,"config":501},"Automated Software Delivery",{"href":485,"dataGaLocation":422,"dataGaName":502},"Automated software delivery",{"title":504,"description":505,"link":506,"items":511},"Security","Deliver code faster without compromising security",{"config":507},{"href":508,"dataGaName":509,"dataGaLocation":422,"icon":510},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[512,516,521],{"text":513,"config":514},"Application Security Testing",{"href":508,"dataGaName":515,"dataGaLocation":422},"Application security testing",{"text":517,"config":518},"Software Supply Chain Security",{"href":519,"dataGaLocation":422,"dataGaName":520},"/solutions/supply-chain/","Software supply chain security",{"text":522,"config":523},"Software Compliance",{"href":524,"dataGaName":525,"dataGaLocation":422},"/solutions/software-compliance/","software compliance",{"title":527,"link":528,"items":533},"Measurement",{"config":529},{"icon":530,"href":531,"dataGaName":532,"dataGaLocation":422},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[534,538,542],{"text":535,"config":536},"Visibility & Measurement",{"href":531,"dataGaLocation":422,"dataGaName":537},"Visibility and Measurement",{"text":539,"config":540},"Value Stream Management",{"href":541,"dataGaLocation":422,"dataGaName":539},"/solutions/value-stream-management/",{"text":543,"config":544},"Analytics & Insights",{"href":545,"dataGaLocation":422,"dataGaName":546},"/solutions/analytics-and-insights/","Analytics and insights",{"title":548,"type":473,"items":549},"GitLab for",[550,556,562],{"text":551,"config":552},"Enterprise",{"icon":553,"href":554,"dataGaLocation":422,"dataGaName":555},"Building","/enterprise/","enterprise",{"text":557,"config":558},"Small Business",{"icon":559,"href":560,"dataGaLocation":422,"dataGaName":561},"Work","/small-business/","small business",{"text":563,"config":564},"Public Sector",{"icon":565,"href":566,"dataGaLocation":422,"dataGaName":567},"Organization","/solutions/public-sector/","public sector",{"text":569,"config":570},"Pricing",{"href":571,"dataGaName":572,"dataGaLocation":422,"dataNavLevelOne":572},"/pricing/","pricing",{"text":574,"config":575,"menu":577},"Resources",{"dataNavLevelOne":576},"resources",{"type":473,"link":578,"columns":582,"feature":676},{"text":579,"config":580},"View all resources",{"href":581,"dataGaName":576,"dataGaLocation":422},"/resources/",[583,616,643],{"title":584,"items":585},"Getting started",[586,591,596,601,606,611],{"text":587,"config":588},"Install",{"href":589,"dataGaName":590,"dataGaLocation":422},"/install/","install",{"text":592,"config":593},"Quick start guides",{"href":594,"dataGaName":595,"dataGaLocation":422},"/get-started/","quick setup checklists",{"text":597,"config":598},"Learn",{"href":599,"dataGaLocation":422,"dataGaName":600},"https://university.gitlab.com/","learn",{"text":602,"config":603},"Product documentation",{"href":604,"dataGaName":605,"dataGaLocation":422},"https://docs.gitlab.com/","product documentation",{"text":607,"config":608},"Best practice videos",{"href":609,"dataGaName":610,"dataGaLocation":422},"/getting-started-videos/","best practice videos",{"text":612,"config":613},"Integrations",{"href":614,"dataGaName":615,"dataGaLocation":422},"/integrations/","integrations",{"title":617,"items":618},"Discover",[619,624,629,634,638],{"text":620,"config":621},"Customer success stories",{"href":622,"dataGaName":623,"dataGaLocation":422},"/customers/","customer success stories",{"text":625,"config":626},"Blog",{"href":627,"dataGaName":628,"dataGaLocation":422},"/blog/","blog",{"text":630,"config":631},"Demo Hub",{"href":632,"dataGaName":633,"dataGaLocation":422},"/demo-hub/","demo hub",{"text":635,"config":636},"The Source",{"href":637,"dataGaName":628,"dataGaLocation":422},"/the-source/",{"text":639,"config":640},"Remote",{"href":641,"dataGaName":642,"dataGaLocation":422},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":644,"items":645},"Connect",[646,651,656,661,666,671],{"text":647,"config":648},"GitLab Services",{"href":649,"dataGaName":650,"dataGaLocation":422},"/services/","services",{"text":652,"config":653},"Contribute",{"href":654,"dataGaName":655,"dataGaLocation":422},"https://contributors.gitlab.com","contribute",{"text":657,"config":658},"Community",{"href":659,"dataGaName":660,"dataGaLocation":422},"/community/","community",{"text":662,"config":663},"Forum",{"href":664,"dataGaName":665,"dataGaLocation":422},"https://forum.gitlab.com/","forum",{"text":667,"config":668},"Events",{"href":669,"dataGaName":670,"dataGaLocation":422},"/events/","events",{"text":672,"config":673},"Partners",{"href":674,"dataGaName":675,"dataGaLocation":422},"/partners/","partners",{"config":677,"title":680,"text":681,"link":682},{"background":678,"textColor":679},"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":683,"config":684},"Read the latest",{"href":685,"dataGaName":686,"dataGaLocation":422},"/whats-new/","whats new",{"text":688,"config":689,"menu":691},"Company",{"dataNavLevelOne":690},"company",{"type":473,"columns":692},[693],{"items":694},[695,700,706,708,713,718,723,728,733,738],{"text":696,"config":697},"About",{"href":698,"dataGaName":699,"dataGaLocation":422},"/company/","about",{"text":701,"config":702,"footerGa":705},"Jobs",{"href":703,"dataGaName":704,"dataGaLocation":422},"/jobs/","jobs",{"dataGaName":704},{"text":667,"config":707},{"href":669,"dataGaName":670,"dataGaLocation":422},{"text":709,"config":710},"Leadership",{"href":711,"dataGaName":712,"dataGaLocation":422},"/company/team/e-group/","leadership",{"text":714,"config":715},"Handbook",{"href":716,"dataGaName":717,"dataGaLocation":422},"https://handbook.gitlab.com/","handbook",{"text":719,"config":720},"Investor relations",{"href":721,"dataGaName":722,"dataGaLocation":422},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":724,"config":725},"Trust Center",{"href":726,"dataGaName":727,"dataGaLocation":422},"/security/","trust center",{"text":729,"config":730},"AI Transparency Center",{"href":731,"dataGaName":732,"dataGaLocation":422},"/ai-transparency-center/","ai transparency center",{"text":734,"config":735},"Newsletter",{"href":736,"dataGaName":737,"dataGaLocation":422},"/company/contact/#contact-forms","newsletter",{"text":739,"config":740},"Press",{"href":741,"dataGaName":742,"dataGaLocation":422},"/press/","press",{"text":744,"config":745,"menu":746},"Contact us",{"dataNavLevelOne":690},{"type":473,"columns":747},[748],{"items":749},[750,755,760],{"text":751,"config":752},"Talk to sales",{"href":753,"dataGaName":754,"dataGaLocation":422},"/sales/","talk to sales",{"text":756,"config":757},"Support portal",{"href":758,"dataGaName":759,"dataGaLocation":422},"https://support.gitlab.com/hc/en-us","support portal",{"text":761,"config":762},"Customer portal",{"href":763,"dataGaName":764,"dataGaLocation":422},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":766,"login":767,"suggestions":774},"Close",{"text":768,"link":769},"To search repositories and projects, login to",{"text":770,"config":771},"gitlab.com",{"href":436,"dataGaName":772,"dataGaLocation":773},"search login","search",{"text":775,"default":776},"Suggestions",[777,779,783,785,789,793],{"text":453,"config":778},{"href":458,"dataGaName":453,"dataGaLocation":773},{"text":780,"config":781},"Code Suggestions (AI)",{"href":782,"dataGaName":780,"dataGaLocation":773},"/solutions/code-suggestions/",{"text":489,"config":784},{"href":491,"dataGaName":489,"dataGaLocation":773},{"text":786,"config":787},"GitLab on AWS",{"href":788,"dataGaName":786,"dataGaLocation":773},"/partners/technology-partners/aws/",{"text":790,"config":791},"GitLab on Google Cloud",{"href":792,"dataGaName":790,"dataGaLocation":773},"/partners/technology-partners/google-cloud-platform/",{"text":794,"config":795},"Why GitLab?",{"href":466,"dataGaName":794,"dataGaLocation":773},{"freeTrial":797,"mobileIcon":802,"desktopIcon":807,"secondaryButton":810},{"text":798,"config":799},"Start free trial",{"href":800,"dataGaName":427,"dataGaLocation":801},"https://gitlab.com/-/trials/new/","nav",{"altText":803,"config":804},"Gitlab Icon",{"src":805,"dataGaName":806,"dataGaLocation":801},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":803,"config":808},{"src":809,"dataGaName":806,"dataGaLocation":801},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":811,"config":812},"Get Started",{"href":813,"dataGaName":814,"dataGaLocation":801},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":816,"mobileIcon":820,"desktopIcon":822},{"text":817,"config":818},"Learn more about GitLab Duo",{"href":458,"dataGaName":819,"dataGaLocation":801},"gitlab duo",{"altText":803,"config":821},{"src":805,"dataGaName":806,"dataGaLocation":801},{"altText":803,"config":823},{"src":809,"dataGaName":806,"dataGaLocation":801},{"button":825,"mobileIcon":830,"desktopIcon":832},{"text":826,"config":827},"/switch",{"href":828,"dataGaName":829,"dataGaLocation":801},"#contact","switch",{"altText":803,"config":831},{"src":805,"dataGaName":806,"dataGaLocation":801},{"altText":803,"config":833},{"src":834,"dataGaName":806,"dataGaLocation":801},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":836,"mobileIcon":841,"desktopIcon":843},{"text":837,"config":838},"Back to pricing",{"href":571,"dataGaName":839,"dataGaLocation":801,"icon":840},"back to pricing","GoBack",{"altText":803,"config":842},{"src":805,"dataGaName":806,"dataGaLocation":801},{"altText":803,"config":844},{"src":809,"dataGaName":806,"dataGaLocation":801},{"title":846,"titleMobile":847,"button":848,"config":853},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":464,"config":849},{"href":850,"dataGaName":851,"dataGaLocation":852},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":854,"disabled":404},"release",{"data":856},{"text":857,"source":858,"edit":864,"contribute":869,"config":874,"items":879,"minimal":1088},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":859,"config":860},"View page source",{"href":861,"dataGaName":862,"dataGaLocation":863},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":865,"config":866},"Edit this page",{"href":867,"dataGaName":868,"dataGaLocation":863},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":870,"config":871},"Please contribute",{"href":872,"dataGaName":873,"dataGaLocation":863},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":875,"facebook":876,"youtube":877,"linkedin":878},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[880,927,980,1024,1056],{"title":569,"links":881,"subMenu":896},[882,886,891],{"text":883,"config":884},"View plans",{"href":571,"dataGaName":885,"dataGaLocation":863},"view plans",{"text":887,"config":888},"Why Premium?",{"href":889,"dataGaName":890,"dataGaLocation":863},"/pricing/premium/","why premium",{"text":892,"config":893},"Why Ultimate?",{"href":894,"dataGaName":895,"dataGaLocation":863},"/pricing/ultimate/","why ultimate",[897],{"title":898,"links":899},"Contact Us",[900,903,905,907,912,917,922],{"text":901,"config":902},"Contact sales",{"href":753,"dataGaName":432,"dataGaLocation":863},{"text":756,"config":904},{"href":758,"dataGaName":759,"dataGaLocation":863},{"text":761,"config":906},{"href":763,"dataGaName":764,"dataGaLocation":863},{"text":908,"config":909},"Status",{"href":910,"dataGaName":911,"dataGaLocation":863},"https://status.gitlab.com/","status",{"text":913,"config":914},"Terms of use",{"href":915,"dataGaName":916,"dataGaLocation":863},"/terms/","terms of use",{"text":918,"config":919},"Privacy statement",{"href":920,"dataGaName":921,"dataGaLocation":863},"/privacy/","privacy statement",{"text":923,"config":924},"Cookie preferences",{"dataGaName":925,"dataGaLocation":863,"id":926,"isOneTrustButton":399},"cookie preferences","ot-sdk-btn",{"title":469,"links":928,"subMenu":936},[929,932],{"text":413,"config":930},{"href":451,"dataGaName":931,"dataGaLocation":863},"devsecops platform",{"text":933,"config":934},"AI-Assisted Development",{"href":458,"dataGaName":935,"dataGaLocation":863},"ai-assisted development",[937],{"title":938,"links":939},"Topics",[940,945,950,955,960,965,970,975],{"text":941,"config":942},"CICD",{"href":943,"dataGaName":944,"dataGaLocation":863},"/topics/ci-cd/","cicd",{"text":946,"config":947},"GitOps",{"href":948,"dataGaName":949,"dataGaLocation":863},"/topics/gitops/","gitops",{"text":951,"config":952},"DevOps",{"href":953,"dataGaName":954,"dataGaLocation":863},"/topics/devops/","devops",{"text":956,"config":957},"Version Control",{"href":958,"dataGaName":959,"dataGaLocation":863},"/topics/version-control/","version control",{"text":961,"config":962},"DevSecOps",{"href":963,"dataGaName":964,"dataGaLocation":863},"/topics/devsecops/","devsecops",{"text":966,"config":967},"Cloud Native",{"href":968,"dataGaName":969,"dataGaLocation":863},"/topics/cloud-native/","cloud native",{"text":971,"config":972},"AI for Coding",{"href":973,"dataGaName":974,"dataGaLocation":863},"/topics/devops/ai-for-coding/","ai for coding",{"text":976,"config":977},"Agentic AI",{"href":978,"dataGaName":979,"dataGaLocation":863},"/topics/agentic-ai/","agentic ai",{"title":981,"links":982},"Solutions",[983,985,987,992,996,999,1003,1006,1008,1011,1014,1019],{"text":513,"config":984},{"href":508,"dataGaName":513,"dataGaLocation":863},{"text":502,"config":986},{"href":485,"dataGaName":486,"dataGaLocation":863},{"text":988,"config":989},"Agile development",{"href":990,"dataGaName":991,"dataGaLocation":863},"/solutions/agile-delivery/","agile delivery",{"text":993,"config":994},"SCM",{"href":498,"dataGaName":995,"dataGaLocation":863},"source code management",{"text":941,"config":997},{"href":491,"dataGaName":998,"dataGaLocation":863},"continuous integration & delivery",{"text":1000,"config":1001},"Value stream management",{"href":541,"dataGaName":1002,"dataGaLocation":863},"value stream management",{"text":946,"config":1004},{"href":1005,"dataGaName":949,"dataGaLocation":863},"/solutions/gitops/",{"text":551,"config":1007},{"href":554,"dataGaName":555,"dataGaLocation":863},{"text":1009,"config":1010},"Small business",{"href":560,"dataGaName":561,"dataGaLocation":863},{"text":1012,"config":1013},"Public sector",{"href":566,"dataGaName":567,"dataGaLocation":863},{"text":1015,"config":1016},"Education",{"href":1017,"dataGaName":1018,"dataGaLocation":863},"/solutions/education/","education",{"text":1020,"config":1021},"Financial services",{"href":1022,"dataGaName":1023,"dataGaLocation":863},"/solutions/finance/","financial services",{"title":574,"links":1025},[1026,1028,1030,1032,1035,1037,1040,1042,1044,1046,1048,1050,1052,1054],{"text":587,"config":1027},{"href":589,"dataGaName":590,"dataGaLocation":863},{"text":592,"config":1029},{"href":594,"dataGaName":595,"dataGaLocation":863},{"text":597,"config":1031},{"href":599,"dataGaName":600,"dataGaLocation":863},{"text":602,"config":1033},{"href":604,"dataGaName":1034,"dataGaLocation":863},"docs",{"text":625,"config":1036},{"href":627,"dataGaName":628,"dataGaLocation":863},{"text":1038,"config":1039},"What's new",{"href":685,"dataGaName":686,"dataGaLocation":863},{"text":620,"config":1041},{"href":622,"dataGaName":623,"dataGaLocation":863},{"text":639,"config":1043},{"href":641,"dataGaName":642,"dataGaLocation":863},{"text":647,"config":1045},{"href":649,"dataGaName":650,"dataGaLocation":863},{"text":652,"config":1047},{"href":654,"dataGaName":655,"dataGaLocation":863},{"text":657,"config":1049},{"href":659,"dataGaName":660,"dataGaLocation":863},{"text":662,"config":1051},{"href":664,"dataGaName":665,"dataGaLocation":863},{"text":667,"config":1053},{"href":669,"dataGaName":670,"dataGaLocation":863},{"text":672,"config":1055},{"href":674,"dataGaName":675,"dataGaLocation":863},{"title":688,"links":1057},[1058,1060,1062,1064,1066,1068,1072,1077,1079,1081,1083],{"text":696,"config":1059},{"href":698,"dataGaName":690,"dataGaLocation":863},{"text":701,"config":1061},{"href":703,"dataGaName":704,"dataGaLocation":863},{"text":709,"config":1063},{"href":711,"dataGaName":712,"dataGaLocation":863},{"text":714,"config":1065},{"href":716,"dataGaName":717,"dataGaLocation":863},{"text":719,"config":1067},{"href":721,"dataGaName":722,"dataGaLocation":863},{"text":1069,"config":1070},"Sustainability",{"href":1071,"dataGaName":1069,"dataGaLocation":863},"/sustainability/",{"text":1073,"config":1074},"Diversity, inclusion and belonging (DIB)",{"href":1075,"dataGaName":1076,"dataGaLocation":863},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":724,"config":1078},{"href":726,"dataGaName":727,"dataGaLocation":863},{"text":734,"config":1080},{"href":736,"dataGaName":737,"dataGaLocation":863},{"text":739,"config":1082},{"href":741,"dataGaName":742,"dataGaLocation":863},{"text":1084,"config":1085},"Modern Slavery Transparency Statement",{"href":1086,"dataGaName":1087,"dataGaLocation":863},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1089},[1090,1093,1096],{"text":1091,"config":1092},"Terms",{"href":915,"dataGaName":916,"dataGaLocation":863},{"text":1094,"config":1095},"Cookies",{"dataGaName":925,"dataGaLocation":863,"id":926,"isOneTrustButton":399},{"text":1097,"config":1098},"Privacy",{"href":920,"dataGaName":921,"dataGaLocation":863},[1100],{"id":1101,"title":7,"body":398,"config":1102,"content":1104,"description":398,"extension":1108,"meta":1109,"navigation":399,"path":1110,"seo":1111,"stem":1112,"__hash__":1113},"blogAuthors/en-us/blog/authors/vishal-tak.yml",{"template":1103},"BlogAuthor",{"name":7,"config":1105},{"headshot":1106,"ctfId":1107},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663854/Blog/Author%20Headshots/vishal_tak_headshot.png","6BalO1YQUIuDdhUP80bFra","yml",{},"/en-us/blog/authors/vishal-tak",{},"en-us/blog/authors/vishal-tak","WQVjyh5oeihTVp9uFThfEtK2F54wNmeVU5OzhSx42vc",[1115,1123,1131],{"title":1116,"description":1117,"heroImage":1118,"category":394,"date":1119,"authors":1120,"slug":1122,"externalUrl":398},"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",[1121],"Julian Thome","improved-scope-offset-fingerprinting",{"title":1124,"description":1125,"heroImage":1118,"category":394,"date":1126,"authors":1127,"slug":1130,"externalUrl":398},"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",[1128,1129],"Erick Bajao","Joe Randazzo","gitlab-secrets-manager-add-eso-terraform-api-support",{"title":1132,"description":1133,"heroImage":1134,"category":394,"date":1135,"authors":1136,"slug":1138,"externalUrl":398},"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",[1137],"Alisa Ho","claude-security-and-gitlab",{"promotions":1140},[1141,1155,1167,1178],{"id":1142,"categories":1143,"header":1145,"text":1146,"button":1147,"image":1152},"ai-modernization",[1144],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1148,"config":1149},"Get your AI maturity score",{"href":1150,"dataGaName":1151,"dataGaLocation":628},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1153},{"src":1154},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1156,"categories":1157,"header":1159,"text":1146,"button":1160,"image":1164},"devops-modernization",[1158,964],"product","Are you just managing tools or shipping innovation?",{"text":1161,"config":1162},"Get your DevOps maturity score",{"href":1163,"dataGaName":1151,"dataGaLocation":628},"/assessments/devops-modernization-assessment/",{"config":1165},{"src":1166},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1168,"categories":1169,"header":1170,"text":1146,"button":1171,"image":1175},"security-modernization",[394],"Are you trading speed for security?",{"text":1172,"config":1173},"Get your security maturity score",{"href":1174,"dataGaName":1151,"dataGaLocation":628},"/assessments/security-modernization-assessment/",{"config":1176},{"src":1177},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1179,"paths":1180,"header":1183,"text":1184,"button":1185,"image":1190},"github-azure-migration",[1181,1182],"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":1186,"config":1187},"See how GitLab compares to GitHub",{"href":1188,"dataGaName":1189,"dataGaLocation":628},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1191},{"src":1166},{"header":1193,"blurb":1194,"button":1195,"secondaryButton":1200},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1196,"config":1197},"Get your free trial",{"href":1198,"dataGaName":427,"dataGaLocation":1199},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":901,"config":1201},{"href":753,"dataGaName":432,"dataGaLocation":1199},1786803748828]