[{"data":1,"prerenderedAt":1275},["ShallowReactive",2],{"/blog/cicd-tunnel-impersonation":3,"navigation-en-us":487,"banner-en-us":915,"footer-en-us":925,"blog-post-authors-en-us-Cesar Saavedra":1170,"blog-related-posts-en-us-cicd-tunnel-impersonation":1185,"blog-promotions-en-us":1211,"next-steps-en-us":1265},{"id":4,"title":5,"authors":6,"body":8,"category":463,"date":464,"description":465,"extension":466,"externalUrl":467,"faq":467,"featured":468,"heroImage":469,"meta":470,"navigation":471,"path":472,"seo":473,"slug":478,"stem":479,"tags":480,"template":485,"updatedDate":467,"__hash__":486},"blogPosts/en-us/blog/cicd-tunnel-impersonation.md","How to use fine-grained permissions via generic impersonation in CI/CD Tunnel",[7],"Cesar Saavedra",{"type":9,"value":10,"toc":446},"minimark",[11,28,33,36,39,42,58,61,64,72,76,79,84,87,95,99,108,115,118,121,124,131,134,141,145,148,155,158,165,168,175,178,185,193,200,203,210,213,220,223,230,234,237,244,248,251,258,266,273,276,283,287,290,297,300,307,311,314,321,324,331,334,341,344,351,355,358,365,368,375,378,385,388,395,398,405,408,415,419,422,425,438],[12,13,14,15,21,22,27],"p",{},"The ",[16,17,20],"a",{"href":18,"rel":19},"https://docs.gitlab.com/user/clusters/agent/ci_cd_workflow/",[],"CI/CD Tunnel",", which leverages the ",[16,23,26],{"href":24,"rel":25},"https://docs.gitlab.com/user/clusters/agent/",[],"GitLab Agent for Kubernetes",", enables users to access Kubernetes clusters from GitLab CI/CD jobs. In this blog post, we review how you can securely access your clusters from your CI/CD pipelines by using generic impersonation. In addition, we will briefly cover the activity list of the GitLab Agent for Kubernetes, a capability recently introduced by GitLab, that can help you detect and troubleshoot faulty events.",[29,30,32],"h2",{"id":31},"using-impersonation-with-your-cicd-tunnel","Using impersonation with your CI/CD tunnel",[12,34,35],{},"The CI/CD Tunnel leverages the GitLab Agent for Kubernetes, which permits the secure connectivity between GitLab and your Kubernetes cluster without the need to expose your cluster to the internet and outside your firewall. The CI/CD Tunnel allows you to connect to your Kubernetes cluster from your CI/CD jobs/pipelines.",[12,37,38],{},"By default, the CI/CD Tunnel inherits all the permissions from the service account used to install the Agent in the cluster. However, fine-grained permissions can be used in conjunction with the CI/CD Tunnel to restrict and manage access to your cluster resources.",[12,40,41],{},"Fine-grained permissions control with the CI/CD tunnel via impersonation:",[43,44,45,49,52,55],"ul",{},[46,47,48],"li",{},"Allows you to leverage your K8s authorization capabilities to limit the permissions of what can be done with the CI/CD tunnel on your running cluster",[46,50,51],{},"Lowers the risk of providing unlimited access to your K8s cluster with the CI/CD tunnel",[46,53,54],{},"Segments fine-grained permissions with the CI/CD tunnel at the project or group level",[46,56,57],{},"Controls permissions with the CI/CD tunnel at the username or service account",[12,59,60],{},"To restrict access to your cluster, you can use impersonation. To specify impersonations, use the access_as attribute in your Agent's configuration file and use Kubernetes RBAC rules to manage impersonated account permissions.",[12,62,63],{},"You can impersonate:",[43,65,66,69],{},[46,67,68],{},"The Agent itself (default)\n= The CI job that accesses the cluster",[46,70,71],{},"A specific user or system account defined within the cluster",[29,73,75],{"id":74},"steps-to-exercise-impersonation-with-the-cicd-tunnel","Steps to exercise impersonation with the CI/CD Tunnel",[12,77,78],{},"Let's go through the steps on how you can exercise impersonation with the CI/CD Tunnel.",[80,81,83],"h3",{"id":82},"creating-your-kubernetes-cluster","Creating your Kubernetes cluster",[12,85,86],{},"In order to exercise the capabilities described above, we need a Kubernetes cluster. Although, you can use any Kubernetes distribution, for this example, we create a GKE Standard Kubernetes cluster and name it \"csaavedra-ga4k-cluster\". We select the zone and version 1.21 of Kubernetes and ensure that our cluster will have three nodes. We leave the security and metadata screens with their defaulted values and click on the create button:",[12,88,89,94],{},[90,91],"img",{"alt":92,"src":93},"Creating a GKE cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398065/blog/Content%20Images/cicd-tunnel-impersonate/0-gke-creation.png","\nCreating a GKE cluster",[80,96,98],{"id":97},"sample-projects-to-be-used","Sample projects to be used",[12,100,101,102,107],{},"Let's proceed now to this ",[16,103,106],{"href":104,"rel":105},"https://gitlab.com/tech-marketing/sandbox/gl-14-5-cs-demos",[],"top-level group",", which contains three projects, which we will use to show impersonation with the CI/CD tunnel. You can do this at the project or group level. In this example, we will show setting impersonation at the project level:",[12,109,110,114],{},[90,111],{"alt":112,"src":113},"Project structure in GitLab","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398065/blog/Content%20Images/cicd-tunnel-impersonate/1-project-struct.png","\nProject structure in GitLab",[12,116,117],{},"Project \"ga4k\" will configure the GitLab Agent for Kubernetes and also set impersonations with the CI/CD tunnel. Project \"sample-application\" will use the CI/CD tunnel, managed by the agent, to connect to the Kubernetes cluster and execute a pipeline using different impersonations. Project \"cluster-management\" will also use the CI/CD tunnel to connect to the cluster and install the Ingress application on it.",[12,119,120],{},"Not only does the CI/CD tunnel streamline the deployment, management, and monitoring of Kubernetes-native applications, but it also does it securely and safely by using impersonations that leverage your Kubernetes cluster's RBAC rules.",[12,122,123],{},"Project \"ga4k\" contains and manages the configuration for the GitLab Agent for K8s called \"csaavedra-agentk\". Looking at its \"config.yaml\" file, we see that the agent points to itself for manifest projects, but most importantly, it provides CI/CD tunnel access to two projects: \"sample-application\" and \"cluster-management\". This means that these two projects' CI/CD pipelines will have access to the K8s cluster that the agent is securely connected to:",[12,125,126,130],{},[90,127],{"alt":128,"src":129},"The GitLab Agent for K8s configuration","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398070/blog/Content%20Images/cicd-tunnel-impersonate/2-agent-config.png","\nThe GitLab Agent for K8s configuration",[12,132,133],{},"Project \"sample-application\" has a pipeline, which we will later execute under different impersonations. And project \"cluster-management\" has a pipeline that will install only the Ingress application on the Kubernetes cluster, as configured in its helmfile.yaml file:",[12,135,136,140],{},[90,137],{"alt":138,"src":139},"Deployable applications in cluster-management project","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398075/blog/Content%20Images/cicd-tunnel-impersonate/3-cluster-mgmt-helmfile.png","\nDeployable applications in cluster-management project",[80,142,144],{"id":143},"connecting-the-agent-to-your-kubernetes-cluster","Connecting the Agent to your Kubernetes cluster",[12,146,147],{},"Let's head back to project \"ga4k\" and connect to the Kubernetes cluster via the agent. We select agent \"csaavedra-agentk\" to register with GitLab:",[12,149,150,154],{},[90,151],{"alt":152,"src":153},"List of defined agents","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398074/blog/Content%20Images/cicd-tunnel-impersonate/4-agents-popdown.png","\nList of defined agents",[12,156,157],{},"This step generates a token that we can use to install the agent on the cluster. We copy the Docker command to our local desktop for later use. Notice that the command includes the generated token, which you can also copy:",[12,159,160,164],{},[90,161],{"alt":162,"src":163},"Docker command to deploy agent to your K8s cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398074/blog/Content%20Images/cicd-tunnel-impersonate/5-docker-cmd.png","\nDocker command to deploy agent to your K8s cluster",[12,166,167],{},"From a local command window, we ensure that our connectivity parameters to GCP are correct:",[12,169,170,174],{},[90,171],{"alt":172,"src":173},"Checking your GCP connectivity parameters","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398074/blog/Content%20Images/cicd-tunnel-impersonate/6-gcp-connectivity.png","\nChecking your GCP connectivity parameters",[12,176,177],{},"We then add the credentials to our kubeconfig file to connect to our newly created Kubernetes cluster \"csaavedra-ga4k-cluster\" and verify that our context is set to it:",[12,179,180,184],{},[90,181],{"alt":182,"src":183},"Adding your cluster credentials to your kubeconfig","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398075/blog/Content%20Images/cicd-tunnel-impersonate/7-adding-creds.png","\nAdding the credentials of your cluster to your kubeconfig",[12,186,187,188,192],{},"Once this is done, we can list all the pods that are up and running on the cluster by entering ",[189,190,191],"code",{},"kubectl get pods –all-namespaces",":",[12,194,195,199],{},[90,196],{"alt":197,"src":198},"Listing the pods in your running cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398075/blog/Content%20Images/cicd-tunnel-impersonate/8-listing-pods.png","\nListing the pods in your running cluster",[12,201,202],{},"Finally, we paste the docker command that will install the GitLab Agent for Kubernetes to this cluster making sure that its namespace is \"ga4k-agent\":",[12,204,205,209],{},[90,206],{"alt":207,"src":208},"Deploying the agent to your K8s cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398075/blog/Content%20Images/cicd-tunnel-impersonate/9-pasted-docker-cmd.png","\nDeploying the agent to your K8s cluster",[12,211,212],{},"We list the pods one more time to check that the agent pod is up and running on the cluster:",[12,214,215,219],{},[90,216],{"alt":217,"src":218},"Agent up and running on your K8s cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398065/blog/Content%20Images/cicd-tunnel-impersonate/10-agent-up.png","\nAgent up and running on your K8s cluster",[12,221,222],{},"The screen will refresh and show our Kubernetes cluster connected via the agent:",[12,224,225,229],{},[90,226],{"alt":227,"src":228},"Agent connected to your K8s cluster","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/11-agent-connected.png","\nAgent connected to your K8s cluster",[80,231,233],{"id":232},"the-agents-activity-information-page","The Agent's Activity Information page",[12,235,236],{},"Clicking on the agent name takes us to the Agent's Activity Information page, which lists agent events in real time. This information can help monitor your cluster's activity and detect and troubleshoot faulty events from your cluster. Connection and token information is currently listed with more events coming in future releases:",[12,238,239,243],{},[90,240],{"alt":241,"src":242},"Agent activity information page","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/12-agent-activity.png","\nAgent activity information page",[80,245,247],{"id":246},"deploying-ingress-to-your-kubernetes-cluster-using-default-impersonation","Deploying Ingress to your Kubernetes cluster using default impersonation",[12,249,250],{},"By default, the CI/CD Tunnel inherits all the permissions from the service account used to install the agent in the cluster. Per the agent's configuration, the CI/CD pipelines of the \"cluster-management\" project will have access to the K8s cluster that the agent is securely connected to. Let's leverage this connectivity to deploy the Ingress application to the Kubernetes cluster from project \"cluster-management\". Let's make a small update to the project pipeline to launch it. Once the pipeline launches, we navigate to its detail view to track its completion:",[12,252,253,257],{},[90,254],{"alt":255,"src":256},"Project \"cluster-management\" pipeline completed","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/13-cluster-mgmt-pipeline.png","\nProject \"cluster-management\" pipeline completed",[12,259,260,261,265],{},"and check the log of its ",[262,263,264],"strong",{},"apply"," job to verify that it was able to switch to the agent's context and successfully ran all the installation steps:",[12,267,268,272],{},[90,269],{"alt":270,"src":271},"Ingress deployed to your cluster via CI/CD Tunnel using default impersonation","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/14-apply-job-log.png","\nIngress deployed to your cluster via CI/CD Tunnel using default impersonation",[12,274,275],{},"For further verification, we list the pods in the cluster and check that the ingress pods are up and running:",[12,277,278,282],{},[90,279],{"alt":280,"src":281},"Ingress pods up and running","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/15-ingress-pods-up.png","\nIngress pods up and running on your cluster",[80,284,286],{"id":285},"start-trailing-the-agents-log-file-to-watch-updates","Start trailing the agent's log file to watch updates",[12,288,289],{},"Before we start the impersonation use cases, let's start trailing the agent's log file from a command window:",[12,291,292,296],{},[90,293],{"alt":294,"src":295},"Trailing agent log from the command line","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398066/blog/Content%20Images/cicd-tunnel-impersonate/16-trail-agent-log.png","\nTrailing agent log from the command line",[12,298,299],{},"And also let's increase its logging to debug:",[12,301,302,306],{},[90,303],{"alt":304,"src":305},"Increasing the agent log level to debug","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398068/blog/Content%20Images/cicd-tunnel-impersonate/17-agent-logging-level.png","\nIncreasing the agent log level to debug",[80,308,310],{"id":309},"running-impersonation-using-access_asci_job","Running impersonation using access_as:ci_job",[12,312,313],{},"Let's now impersonate the CI job that accesses the cluster. For this, we modify the agent's configuration and add the \"access_as\" attribute with the \"ci_job\" tag under it:",[12,315,316,320],{},[90,317],{"alt":318,"src":319},"Impersonating the CI job","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398069/blog/Content%20Images/cicd-tunnel-impersonate/18-ci-job-impersonation.png","\nImpersonating the CI job",[12,322,323],{},"As we save the updated configuration, we verify in the log output that the update has taken place in the running agent:",[12,325,326,330],{},[90,327],{"alt":328,"src":329},"Agent updated with CI job impersonation","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398069/blog/Content%20Images/cicd-tunnel-impersonate/19-agent-conf-updated.png","\nAgent updated with CI job impersonation",[12,332,333],{},"Notice that the pipeline of the \"sample-application\" project has a test stage and a test job. It sets the variable KUBE_CONTEXT first, loads an image with the version of kubectl that matches the version of the K8s cluster, and executes two kubectl commands that access the remote cluster via the agent:",[12,335,336,340],{},[90,337],{"alt":338,"src":339},"Project \"sample-application\" pipeline","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398070/blog/Content%20Images/cicd-tunnel-impersonate/20-sample-application-pipeline.png","\nProject \"sample-application\" pipeline",[12,342,343],{},"We manually execute the pipeline of the \"sample-application\" project and verify in the job log output that the context switch was successful and that the kubectl commands executed correctly:",[12,345,346,350],{},[90,347],{"alt":348,"src":349},"Job log output with CI impersonation","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398070/blog/Content%20Images/cicd-tunnel-impersonate/21-ci-impersonation-job-log.png","\nJob log output with CI impersonation",[80,352,354],{"id":353},"running-impersonation-using-access_asimpersonateusername","Running impersonation using access_as:impersonate:username",[12,356,357],{},"The last use case is the impersonation of a specific user or system account defined within the cluster. I have pre-created a service account called \"jane\" on the Kubernetes cluster under the \"default\" namespace. And \"jane\" has been given the permission to do a \"get\", \"list\", and \"watch\" on the cluster pods as you can see by the output in the command window:",[12,359,360,364],{},[90,361],{"alt":362,"src":363},"Jane user with permission to list pods","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398070/blog/Content%20Images/cicd-tunnel-impersonate/22-jane-and-perms.png","\nJane user with permission to list pods",[12,366,367],{},"Remember that the service account \"gitlab-agent\" under namespace \"ga4k-agent\" was created earlier when we installed the agent by running the Docker command. In order for the agent to be able to impersonate another service account or user, it needs to have the permissions to do so. We do this by creating a clusterrole \"impersonate\" for impersonating users, groups, and service accounts, and then create a clusterrolebinding \"allowimpersonator\" to give these permissions for the \"default\" namespace to the agent \"gitlab-agent\" in the \"ga4k-agent\" namespace:",[12,369,370,374],{},[90,371],{"alt":372,"src":373},"Giving impersonation permission to agent","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398071/blog/Content%20Images/cicd-tunnel-impersonate/23-clusterrole-perm-to-agent.png","\nGiving impersonation permission to agent",[12,376,377],{},"We then edit the agent's configuration and add the \"impersonate\" attribute and provide the service account for \"jane\" as the parameter for the \"username\" tag:",[12,379,380,384],{},[90,381],{"alt":382,"src":383},"Impersonating a specific user","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398071/blog/Content%20Images/cicd-tunnel-impersonate/24-user-impersonation.png","\nImpersonating a specific user called jane",[12,386,387],{},"As we commit the changes, we check the log output to verify that the update has taken place in the running agent:",[12,389,390,394],{},[90,391],{"alt":392,"src":393},"Agent updated with user impersonation","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398072/blog/Content%20Images/cicd-tunnel-impersonate/25-agent-conf-updated.png","\nAgent updated with user impersonation",[12,396,397],{},"Since we know that \"jane\" has the permission to list the running pods in the cluster, let's head to the project \"sample-application\" pipeline and add the command \"kubectl get pods –all-namespaces\" to it:",[12,399,400,404],{},[90,401],{"alt":402,"src":403},"Adding get pods command that jane is allowed to run","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398073/blog/Content%20Images/cicd-tunnel-impersonate/26-adding-get-pods-cmd.png","\nAdding get pods command that jane is allowed to run",[12,406,407],{},"We commit the update and head over to the running pipeline and drill into the \"test\" job log output to see that the context switch was successful and that the kubectl commands executed correctly, including the listing of the running pods in the cluster:",[12,409,410,414],{},[90,411],{"alt":412,"src":413},"Job output for pipeline impersonation jane","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398074/blog/Content%20Images/cicd-tunnel-impersonate/27-user-impersonation-job-log.png","\nJob output for pipeline impersonation jane",[29,416,418],{"id":417},"conclusion","Conclusion",[12,420,421],{},"In this blog post, we reviewed how you can securely access your Kubernetes clusters from your CI/CD pipelines by using generic impersonation.  In addition, we showed the activity list of the GitLab Agent for Kubernetes, which can help you detect and troubleshoot faulty events from your cluster.",[12,423,424],{},"To see these capabilities in action, check out the following video:",[426,427,430,431],"figure",{"className":428},[429],"video_container","\n  ",[432,433,437],"iframe",{"src":434,"frameBorder":435,"allowFullScreen":436},"https://www.youtube.com/embed/j8SJuHd7Zsw","0","true"," ",[12,439,440,441],{},"Cover image by Jakob Søby on ",[16,442,445],{"href":443,"rel":444},"https://www.unsplash.com",[],"Unsplash",{"title":447,"searchDepth":448,"depth":448,"links":449},"",2,[450,451,462],{"id":31,"depth":448,"text":32},{"id":74,"depth":448,"text":75,"children":452},[453,455,456,457,458,459,460,461],{"id":82,"depth":454,"text":83},3,{"id":97,"depth":454,"text":98},{"id":143,"depth":454,"text":144},{"id":232,"depth":454,"text":233},{"id":246,"depth":454,"text":247},{"id":285,"depth":454,"text":286},{"id":309,"depth":454,"text":310},{"id":353,"depth":454,"text":354},{"id":417,"depth":448,"text":418},"engineering","2022-02-01","Learn how to use use fine-grained permissions via generic impersonation in CI/CD Tunnel","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667435/Blog/Hero%20Images/tunnel.jpg",{},true,"/en-us/blog/cicd-tunnel-impersonation",{"title":474,"description":465,"ogTitle":474,"ogDescription":465,"noIndex":468,"ogImage":469,"ogUrl":475,"ogSiteName":476,"ogType":477,"canonicalUrls":475},"Fine-grained permissions with impersonation in CI/CD tunnel","https://about.gitlab.com/blog/cicd-tunnel-impersonation","https://about.gitlab.com","article","cicd-tunnel-impersonation","en-us/blog/cicd-tunnel-impersonation",[481,482,483,484],"releases","CI","CD","kubernetes","BlogPost","_TQLff9NF29aobnpTs00aEA8gCRY1SRgPKeR3RU022Y",{"logo":488,"freeTrial":493,"sales":498,"login":503,"items":508,"search":835,"minimal":866,"duo":885,"switchNav":894,"pricingDeployment":905},{"config":489},{"href":490,"dataGaName":491,"dataGaLocation":492},"/","gitlab logo","header",{"text":494,"config":495},"Get free trial",{"href":496,"dataGaName":497,"dataGaLocation":492},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":499,"config":500},"Request a demo",{"href":501,"dataGaName":502,"dataGaLocation":492},"/sales/?contact-topic=request-demo","sales",{"text":504,"config":505},"Sign in",{"href":506,"dataGaName":507,"dataGaLocation":492},"https://gitlab.com/users/sign_in/","sign in",[509,538,638,643,757,813],{"text":510,"config":511,"menu":513},"Platform",{"dataNavLevelOne":512},"platform",{"type":514,"columns":515},"cards",[516,522,530],{"title":510,"description":517,"link":518},"The intelligent orchestration platform for DevSecOps",{"text":519,"config":520},"Explore our Platform",{"href":521,"dataGaName":512,"dataGaLocation":492},"/platform/",{"title":523,"description":524,"link":525},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":526,"config":527},"Meet GitLab Duo",{"href":528,"dataGaName":529,"dataGaLocation":492},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":531,"description":532,"link":533},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":534,"config":535},"Learn more",{"href":536,"dataGaName":537,"dataGaLocation":492},"/why-gitlab/","why gitlab",{"text":539,"left":471,"config":540,"menu":542},"Product",{"dataNavLevelOne":541},"solutions",{"type":543,"link":544,"columns":548,"feature":617},"lists",{"text":545,"config":546},"View all Solutions",{"href":547,"dataGaName":541,"dataGaLocation":492},"/solutions/",[549,573,596],{"title":550,"description":551,"link":552,"items":557},"Automation","CI/CD and automation to accelerate deployment",{"config":553},{"icon":554,"href":555,"dataGaName":556,"dataGaLocation":492},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[558,562,565,569],{"text":559,"config":560},"CI/CD",{"href":561,"dataGaLocation":492,"dataGaName":559},"/solutions/continuous-integration/",{"text":523,"config":563},{"href":528,"dataGaLocation":492,"dataGaName":564},"gitlab duo agent platform - product menu",{"text":566,"config":567},"Source Code Management",{"href":568,"dataGaLocation":492,"dataGaName":566},"/solutions/source-code-management/",{"text":570,"config":571},"Automated Software Delivery",{"href":555,"dataGaLocation":492,"dataGaName":572},"Automated software delivery",{"title":574,"description":575,"link":576,"items":581},"Security","Deliver code faster without compromising security",{"config":577},{"href":578,"dataGaName":579,"dataGaLocation":492,"icon":580},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[582,586,591],{"text":583,"config":584},"Application Security Testing",{"href":578,"dataGaName":585,"dataGaLocation":492},"Application security testing",{"text":587,"config":588},"Software Supply Chain Security",{"href":589,"dataGaLocation":492,"dataGaName":590},"/solutions/supply-chain/","Software supply chain security",{"text":592,"config":593},"Software Compliance",{"href":594,"dataGaName":595,"dataGaLocation":492},"/solutions/software-compliance/","software compliance",{"title":597,"link":598,"items":603},"Measurement",{"config":599},{"icon":600,"href":601,"dataGaName":602,"dataGaLocation":492},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[604,608,612],{"text":605,"config":606},"Visibility & Measurement",{"href":601,"dataGaLocation":492,"dataGaName":607},"Visibility and Measurement",{"text":609,"config":610},"Value Stream Management",{"href":611,"dataGaLocation":492,"dataGaName":609},"/solutions/value-stream-management/",{"text":613,"config":614},"Analytics & Insights",{"href":615,"dataGaLocation":492,"dataGaName":616},"/solutions/analytics-and-insights/","Analytics and insights",{"title":618,"type":543,"items":619},"GitLab for",[620,626,632],{"text":621,"config":622},"Enterprise",{"icon":623,"href":624,"dataGaLocation":492,"dataGaName":625},"Building","/enterprise/","enterprise",{"text":627,"config":628},"Small Business",{"icon":629,"href":630,"dataGaLocation":492,"dataGaName":631},"Work","/small-business/","small business",{"text":633,"config":634},"Public Sector",{"icon":635,"href":636,"dataGaLocation":492,"dataGaName":637},"Organization","/solutions/public-sector/","public sector",{"text":639,"config":640},"Pricing",{"href":641,"dataGaName":642,"dataGaLocation":492,"dataNavLevelOne":642},"/pricing/","pricing",{"text":644,"config":645,"menu":647},"Resources",{"dataNavLevelOne":646},"resources",{"type":543,"link":648,"columns":652,"feature":746},{"text":649,"config":650},"View all resources",{"href":651,"dataGaName":646,"dataGaLocation":492},"/resources/",[653,686,713],{"title":654,"items":655},"Getting started",[656,661,666,671,676,681],{"text":657,"config":658},"Install",{"href":659,"dataGaName":660,"dataGaLocation":492},"/install/","install",{"text":662,"config":663},"Quick start guides",{"href":664,"dataGaName":665,"dataGaLocation":492},"/get-started/","quick setup checklists",{"text":667,"config":668},"Learn",{"href":669,"dataGaLocation":492,"dataGaName":670},"https://university.gitlab.com/","learn",{"text":672,"config":673},"Product documentation",{"href":674,"dataGaName":675,"dataGaLocation":492},"https://docs.gitlab.com/","product documentation",{"text":677,"config":678},"Best practice videos",{"href":679,"dataGaName":680,"dataGaLocation":492},"/getting-started-videos/","best practice videos",{"text":682,"config":683},"Integrations",{"href":684,"dataGaName":685,"dataGaLocation":492},"/integrations/","integrations",{"title":687,"items":688},"Discover",[689,694,699,704,708],{"text":690,"config":691},"Customer success stories",{"href":692,"dataGaName":693,"dataGaLocation":492},"/customers/","customer success stories",{"text":695,"config":696},"Blog",{"href":697,"dataGaName":698,"dataGaLocation":492},"/blog/","blog",{"text":700,"config":701},"Demo Hub",{"href":702,"dataGaName":703,"dataGaLocation":492},"/demo-hub/","demo hub",{"text":705,"config":706},"The Source",{"href":707,"dataGaName":698,"dataGaLocation":492},"/the-source/",{"text":709,"config":710},"Remote",{"href":711,"dataGaName":712,"dataGaLocation":492},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":714,"items":715},"Connect",[716,721,726,731,736,741],{"text":717,"config":718},"GitLab Services",{"href":719,"dataGaName":720,"dataGaLocation":492},"/services/","services",{"text":722,"config":723},"Contribute",{"href":724,"dataGaName":725,"dataGaLocation":492},"https://contributors.gitlab.com","contribute",{"text":727,"config":728},"Community",{"href":729,"dataGaName":730,"dataGaLocation":492},"/community/","community",{"text":732,"config":733},"Forum",{"href":734,"dataGaName":735,"dataGaLocation":492},"https://forum.gitlab.com/","forum",{"text":737,"config":738},"Events",{"href":739,"dataGaName":740,"dataGaLocation":492},"/events/","events",{"text":742,"config":743},"Partners",{"href":744,"dataGaName":745,"dataGaLocation":492},"/partners/","partners",{"config":747,"title":750,"text":751,"link":752},{"background":748,"textColor":749},"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":753,"config":754},"Read the latest",{"href":755,"dataGaName":756,"dataGaLocation":492},"/whats-new/","whats new",{"text":758,"config":759,"menu":761},"Company",{"dataNavLevelOne":760},"company",{"type":543,"columns":762},[763],{"items":764},[765,770,776,778,783,788,793,798,803,808],{"text":766,"config":767},"About",{"href":768,"dataGaName":769,"dataGaLocation":492},"/company/","about",{"text":771,"config":772,"footerGa":775},"Jobs",{"href":773,"dataGaName":774,"dataGaLocation":492},"/jobs/","jobs",{"dataGaName":774},{"text":737,"config":777},{"href":739,"dataGaName":740,"dataGaLocation":492},{"text":779,"config":780},"Leadership",{"href":781,"dataGaName":782,"dataGaLocation":492},"/company/team/e-group/","leadership",{"text":784,"config":785},"Handbook",{"href":786,"dataGaName":787,"dataGaLocation":492},"https://handbook.gitlab.com/","handbook",{"text":789,"config":790},"Investor relations",{"href":791,"dataGaName":792,"dataGaLocation":492},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":794,"config":795},"Trust Center",{"href":796,"dataGaName":797,"dataGaLocation":492},"/security/","trust center",{"text":799,"config":800},"AI Transparency Center",{"href":801,"dataGaName":802,"dataGaLocation":492},"/ai-transparency-center/","ai transparency center",{"text":804,"config":805},"Newsletter",{"href":806,"dataGaName":807,"dataGaLocation":492},"/company/contact/#contact-forms","newsletter",{"text":809,"config":810},"Press",{"href":811,"dataGaName":812,"dataGaLocation":492},"/press/","press",{"text":814,"config":815,"menu":816},"Contact us",{"dataNavLevelOne":760},{"type":543,"columns":817},[818],{"items":819},[820,825,830],{"text":821,"config":822},"Talk to sales",{"href":823,"dataGaName":824,"dataGaLocation":492},"/sales/","talk to sales",{"text":826,"config":827},"Support portal",{"href":828,"dataGaName":829,"dataGaLocation":492},"https://support.gitlab.com/hc/en-us","support portal",{"text":831,"config":832},"Customer portal",{"href":833,"dataGaName":834,"dataGaLocation":492},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":836,"login":837,"suggestions":844},"Close",{"text":838,"link":839},"To search repositories and projects, login to",{"text":840,"config":841},"gitlab.com",{"href":506,"dataGaName":842,"dataGaLocation":843},"search login","search",{"text":845,"default":846},"Suggestions",[847,849,853,855,859,863],{"text":523,"config":848},{"href":528,"dataGaName":523,"dataGaLocation":843},{"text":850,"config":851},"Code Suggestions (AI)",{"href":852,"dataGaName":850,"dataGaLocation":843},"/solutions/code-suggestions/",{"text":559,"config":854},{"href":561,"dataGaName":559,"dataGaLocation":843},{"text":856,"config":857},"GitLab on AWS",{"href":858,"dataGaName":856,"dataGaLocation":843},"/partners/technology-partners/aws/",{"text":860,"config":861},"GitLab on Google Cloud",{"href":862,"dataGaName":860,"dataGaLocation":843},"/partners/technology-partners/google-cloud-platform/",{"text":864,"config":865},"Why GitLab?",{"href":536,"dataGaName":864,"dataGaLocation":843},{"freeTrial":867,"mobileIcon":872,"desktopIcon":877,"secondaryButton":880},{"text":868,"config":869},"Start free trial",{"href":870,"dataGaName":497,"dataGaLocation":871},"https://gitlab.com/-/trials/new/","nav",{"altText":873,"config":874},"Gitlab Icon",{"src":875,"dataGaName":876,"dataGaLocation":871},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":873,"config":878},{"src":879,"dataGaName":876,"dataGaLocation":871},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":881,"config":882},"Get Started",{"href":883,"dataGaName":884,"dataGaLocation":871},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":886,"mobileIcon":890,"desktopIcon":892},{"text":887,"config":888},"Learn more about GitLab Duo",{"href":528,"dataGaName":889,"dataGaLocation":871},"gitlab duo",{"altText":873,"config":891},{"src":875,"dataGaName":876,"dataGaLocation":871},{"altText":873,"config":893},{"src":879,"dataGaName":876,"dataGaLocation":871},{"button":895,"mobileIcon":900,"desktopIcon":902},{"text":896,"config":897},"/switch",{"href":898,"dataGaName":899,"dataGaLocation":871},"#contact","switch",{"altText":873,"config":901},{"src":875,"dataGaName":876,"dataGaLocation":871},{"altText":873,"config":903},{"src":904,"dataGaName":876,"dataGaLocation":871},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":906,"mobileIcon":911,"desktopIcon":913},{"text":907,"config":908},"Back to pricing",{"href":641,"dataGaName":909,"dataGaLocation":871,"icon":910},"back to pricing","GoBack",{"altText":873,"config":912},{"src":875,"dataGaName":876,"dataGaLocation":871},{"altText":873,"config":914},{"src":879,"dataGaName":876,"dataGaLocation":871},{"title":916,"titleMobile":917,"button":918,"config":923},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":534,"config":919},{"href":920,"dataGaName":921,"dataGaLocation":922},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":924,"disabled":468},"release",{"data":926},{"text":927,"source":928,"edit":934,"contribute":939,"config":944,"items":949,"minimal":1159},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":929,"config":930},"View page source",{"href":931,"dataGaName":932,"dataGaLocation":933},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":935,"config":936},"Edit this page",{"href":937,"dataGaName":938,"dataGaLocation":933},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":940,"config":941},"Please contribute",{"href":942,"dataGaName":943,"dataGaLocation":933},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":945,"facebook":946,"youtube":947,"linkedin":948},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[950,997,1051,1095,1127],{"title":639,"links":951,"subMenu":966},[952,956,961],{"text":953,"config":954},"View plans",{"href":641,"dataGaName":955,"dataGaLocation":933},"view plans",{"text":957,"config":958},"Why Premium?",{"href":959,"dataGaName":960,"dataGaLocation":933},"/pricing/premium/","why premium",{"text":962,"config":963},"Why Ultimate?",{"href":964,"dataGaName":965,"dataGaLocation":933},"/pricing/ultimate/","why ultimate",[967],{"title":968,"links":969},"Contact Us",[970,973,975,977,982,987,992],{"text":971,"config":972},"Contact sales",{"href":823,"dataGaName":502,"dataGaLocation":933},{"text":826,"config":974},{"href":828,"dataGaName":829,"dataGaLocation":933},{"text":831,"config":976},{"href":833,"dataGaName":834,"dataGaLocation":933},{"text":978,"config":979},"Status",{"href":980,"dataGaName":981,"dataGaLocation":933},"https://status.gitlab.com/","status",{"text":983,"config":984},"Terms of use",{"href":985,"dataGaName":986,"dataGaLocation":933},"/terms/","terms of use",{"text":988,"config":989},"Privacy statement",{"href":990,"dataGaName":991,"dataGaLocation":933},"/privacy/","privacy statement",{"text":993,"config":994},"Cookie preferences",{"dataGaName":995,"dataGaLocation":933,"id":996,"isOneTrustButton":471},"cookie preferences","ot-sdk-btn",{"title":539,"links":998,"subMenu":1007},[999,1003],{"text":1000,"config":1001},"DevSecOps platform",{"href":521,"dataGaName":1002,"dataGaLocation":933},"devsecops platform",{"text":1004,"config":1005},"AI-Assisted Development",{"href":528,"dataGaName":1006,"dataGaLocation":933},"ai-assisted development",[1008],{"title":1009,"links":1010},"Topics",[1011,1016,1021,1026,1031,1036,1041,1046],{"text":1012,"config":1013},"CICD",{"href":1014,"dataGaName":1015,"dataGaLocation":933},"/topics/ci-cd/","cicd",{"text":1017,"config":1018},"GitOps",{"href":1019,"dataGaName":1020,"dataGaLocation":933},"/topics/gitops/","gitops",{"text":1022,"config":1023},"DevOps",{"href":1024,"dataGaName":1025,"dataGaLocation":933},"/topics/devops/","devops",{"text":1027,"config":1028},"Version Control",{"href":1029,"dataGaName":1030,"dataGaLocation":933},"/topics/version-control/","version control",{"text":1032,"config":1033},"DevSecOps",{"href":1034,"dataGaName":1035,"dataGaLocation":933},"/topics/devsecops/","devsecops",{"text":1037,"config":1038},"Cloud Native",{"href":1039,"dataGaName":1040,"dataGaLocation":933},"/topics/cloud-native/","cloud native",{"text":1042,"config":1043},"AI for Coding",{"href":1044,"dataGaName":1045,"dataGaLocation":933},"/topics/devops/ai-for-coding/","ai for coding",{"text":1047,"config":1048},"Agentic AI",{"href":1049,"dataGaName":1050,"dataGaLocation":933},"/topics/agentic-ai/","agentic ai",{"title":1052,"links":1053},"Solutions",[1054,1056,1058,1063,1067,1070,1074,1077,1079,1082,1085,1090],{"text":583,"config":1055},{"href":578,"dataGaName":583,"dataGaLocation":933},{"text":572,"config":1057},{"href":555,"dataGaName":556,"dataGaLocation":933},{"text":1059,"config":1060},"Agile development",{"href":1061,"dataGaName":1062,"dataGaLocation":933},"/solutions/agile-delivery/","agile delivery",{"text":1064,"config":1065},"SCM",{"href":568,"dataGaName":1066,"dataGaLocation":933},"source code management",{"text":1012,"config":1068},{"href":561,"dataGaName":1069,"dataGaLocation":933},"continuous integration & delivery",{"text":1071,"config":1072},"Value stream management",{"href":611,"dataGaName":1073,"dataGaLocation":933},"value stream management",{"text":1017,"config":1075},{"href":1076,"dataGaName":1020,"dataGaLocation":933},"/solutions/gitops/",{"text":621,"config":1078},{"href":624,"dataGaName":625,"dataGaLocation":933},{"text":1080,"config":1081},"Small business",{"href":630,"dataGaName":631,"dataGaLocation":933},{"text":1083,"config":1084},"Public sector",{"href":636,"dataGaName":637,"dataGaLocation":933},{"text":1086,"config":1087},"Education",{"href":1088,"dataGaName":1089,"dataGaLocation":933},"/solutions/education/","education",{"text":1091,"config":1092},"Financial services",{"href":1093,"dataGaName":1094,"dataGaLocation":933},"/solutions/finance/","financial services",{"title":644,"links":1096},[1097,1099,1101,1103,1106,1108,1111,1113,1115,1117,1119,1121,1123,1125],{"text":657,"config":1098},{"href":659,"dataGaName":660,"dataGaLocation":933},{"text":662,"config":1100},{"href":664,"dataGaName":665,"dataGaLocation":933},{"text":667,"config":1102},{"href":669,"dataGaName":670,"dataGaLocation":933},{"text":672,"config":1104},{"href":674,"dataGaName":1105,"dataGaLocation":933},"docs",{"text":695,"config":1107},{"href":697,"dataGaName":698,"dataGaLocation":933},{"text":1109,"config":1110},"What's new",{"href":755,"dataGaName":756,"dataGaLocation":933},{"text":690,"config":1112},{"href":692,"dataGaName":693,"dataGaLocation":933},{"text":709,"config":1114},{"href":711,"dataGaName":712,"dataGaLocation":933},{"text":717,"config":1116},{"href":719,"dataGaName":720,"dataGaLocation":933},{"text":722,"config":1118},{"href":724,"dataGaName":725,"dataGaLocation":933},{"text":727,"config":1120},{"href":729,"dataGaName":730,"dataGaLocation":933},{"text":732,"config":1122},{"href":734,"dataGaName":735,"dataGaLocation":933},{"text":737,"config":1124},{"href":739,"dataGaName":740,"dataGaLocation":933},{"text":742,"config":1126},{"href":744,"dataGaName":745,"dataGaLocation":933},{"title":758,"links":1128},[1129,1131,1133,1135,1137,1139,1143,1148,1150,1152,1154],{"text":766,"config":1130},{"href":768,"dataGaName":760,"dataGaLocation":933},{"text":771,"config":1132},{"href":773,"dataGaName":774,"dataGaLocation":933},{"text":779,"config":1134},{"href":781,"dataGaName":782,"dataGaLocation":933},{"text":784,"config":1136},{"href":786,"dataGaName":787,"dataGaLocation":933},{"text":789,"config":1138},{"href":791,"dataGaName":792,"dataGaLocation":933},{"text":1140,"config":1141},"Sustainability",{"href":1142,"dataGaName":1140,"dataGaLocation":933},"/sustainability/",{"text":1144,"config":1145},"Diversity, inclusion and belonging (DIB)",{"href":1146,"dataGaName":1147,"dataGaLocation":933},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":794,"config":1149},{"href":796,"dataGaName":797,"dataGaLocation":933},{"text":804,"config":1151},{"href":806,"dataGaName":807,"dataGaLocation":933},{"text":809,"config":1153},{"href":811,"dataGaName":812,"dataGaLocation":933},{"text":1155,"config":1156},"Modern Slavery Transparency Statement",{"href":1157,"dataGaName":1158,"dataGaLocation":933},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1160},[1161,1164,1167],{"text":1162,"config":1163},"Terms",{"href":985,"dataGaName":986,"dataGaLocation":933},{"text":1165,"config":1166},"Cookies",{"dataGaName":995,"dataGaLocation":933,"id":996,"isOneTrustButton":471},{"text":1168,"config":1169},"Privacy",{"href":990,"dataGaName":991,"dataGaLocation":933},[1171],{"id":1172,"title":7,"body":467,"config":1173,"content":1175,"description":467,"extension":1179,"meta":1180,"navigation":471,"path":1181,"seo":1182,"stem":1183,"__hash__":1184},"blogAuthors/en-us/blog/authors/cesar-saavedra.yml",{"template":1174},"BlogAuthor",{"name":7,"config":1176},{"headshot":1177,"ctfId":1178},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659600/Blog/Author%20Headshots/csaavedra1-headshot.jpg","csaavedra1","yml",{},"/en-us/blog/authors/cesar-saavedra",{},"en-us/blog/authors/cesar-saavedra","SMqRf-z0W5m5GROz_dXGjmuIb3YaOwm_n_RfeK16GcA",[1186,1195,1203],{"title":1187,"description":1188,"heroImage":1189,"category":463,"date":1190,"authors":1191,"slug":1194,"externalUrl":467},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1192,1193],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1196,"description":1197,"heroImage":1198,"category":463,"date":1199,"authors":1200,"slug":1202,"externalUrl":467},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1201],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1204,"description":1205,"heroImage":1206,"category":463,"date":1207,"authors":1208,"slug":1210,"externalUrl":467},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1209],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1212},[1213,1227,1239,1251],{"id":1214,"categories":1215,"header":1217,"text":1218,"button":1219,"image":1224},"ai-modernization",[1216],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1220,"config":1221},"Get your AI maturity score",{"href":1222,"dataGaName":1223,"dataGaLocation":698},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1225},{"src":1226},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1228,"categories":1229,"header":1231,"text":1218,"button":1232,"image":1236},"devops-modernization",[1230,1035],"product","Are you just managing tools or shipping innovation?",{"text":1233,"config":1234},"Get your DevOps maturity score",{"href":1235,"dataGaName":1223,"dataGaLocation":698},"/assessments/devops-modernization-assessment/",{"config":1237},{"src":1238},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1240,"categories":1241,"header":1243,"text":1218,"button":1244,"image":1248},"security-modernization",[1242],"security","Are you trading speed for security?",{"text":1245,"config":1246},"Get your security maturity score",{"href":1247,"dataGaName":1223,"dataGaLocation":698},"/assessments/security-modernization-assessment/",{"config":1249},{"src":1250},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1252,"paths":1253,"header":1256,"text":1257,"button":1258,"image":1263},"github-azure-migration",[1254,1255],"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":1259,"config":1260},"See how GitLab compares to GitHub",{"href":1261,"dataGaName":1262,"dataGaLocation":698},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1264},{"src":1238},{"header":1266,"blurb":1267,"button":1268,"secondaryButton":1273},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1269,"config":1270},"Get your free trial",{"href":1271,"dataGaName":497,"dataGaLocation":1272},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":971,"config":1274},{"href":823,"dataGaName":502,"dataGaLocation":1272},1786803747875]