[{"data":1,"prerenderedAt":1346},["ShallowReactive",2],{"/blog/how-to-protect-gitlab-connected-ssh-key-with-yubikey":3,"navigation-en-us":560,"banner-en-us":988,"footer-en-us":998,"blog-post-authors-en-us-Brendan O'Leary":1242,"blog-related-posts-en-us-how-to-protect-gitlab-connected-ssh-key-with-yubikey":1257,"blog-promotions-en-us":1283,"next-steps-en-us":1336},{"id":4,"title":5,"authors":6,"body":8,"category":539,"date":540,"description":541,"extension":542,"externalUrl":543,"faq":543,"featured":544,"heroImage":545,"meta":546,"navigation":168,"path":547,"seo":548,"slug":552,"stem":553,"tags":554,"template":558,"updatedDate":543,"__hash__":559},"blogPosts/en-us/blog/how-to-protect-gitlab-connected-ssh-key-with-yubikey.md","How to protect GitLab-connected SSH key with Yubikey",[7],"Brendan O'Leary",{"type":9,"value":10,"toc":530},"minimark",[11,27,30,35,44,62,72,93,96,100,106,117,124,129,132,203,207,213,235,245,396,405,409,422,425,523,526],[12,13,14,20,21,26],"p",{},[15,16,19],"a",{"href":17,"rel":18},"https://docs.gitlab.com/security/two_factor_authentication/",[],"Two-factor authentication"," is one of the best defenses we have as individuals for protecting our accounts and credentials. But not all 2FA methods are created equal. For example, SMS is vulnerable to ",[15,22,25],{"href":23,"rel":24},"https://www.ic3.gov/Media/Y2022/PSA220208",[],"SIM-swapping"," attacks and thus doesn't always provide the extra security we would like.",[12,28,29],{},"Ideally, everything I  want to connect to would use 2FA with dedicated 2FA hardware. With GitLab 14.8, you can now use 2FA hardware to protect your SSH keys, as I explain below.",[31,32,34],"h2",{"id":33},"_2fa-and-ssh-keys","2FA and SSH keys",[12,36,37,38,43],{},"State-of-the-art 2FA uses a physical hardware device – often FIDO/U2F hardware – to verify your presence at the time of authentication. This provides two distinct factors as a means of authentication: something you know (your username and password, for instance) with something you have (the physical device). I have two ",[15,39,42],{"href":40,"rel":41},"https://www.yubico.com/works-with-yubikey/catalog/gitlab/",[],"YubiKey"," devices that I use for this purpose – one that is always in a safe in my house and one that I generally keep with me and the computer I'm using to do work. And I have everything I can secure using this method, including my GitLab account.",[12,45,46,47,51,52,55,56,61],{},"And that does a great job of securing my access to GitLab, the application front end, and the ability to create and modify API keys. But there is another way to authenticate to a git server: SSH keys. In this case, there's only one factor of authorization because the SSH key is on my computer. So you can imagine how excited I was to hear that GitLab added support for ",[48,49,50],"code",{},"ecdsa-sk"," and ",[48,53,54],{},"ed25519-sk"," key types in ",[15,57,60],{"href":58,"rel":59},"https://docs.gitlab.com/releases/#support-for-ecdsa-sk-and-ed25519-sk-ssh-keys",[],"GitLab 14.8",".",[63,64,66,67,51,69,71],"h3",{"id":65},"what-are-ecdsa-sk-and-ed25519-sk","What are ",[48,68,50],{},[48,70,54],{},"?",[12,73,74,75,78,79,82,83,86,87,92],{},"These two new keys are close to the existing ",[48,76,77],{},"ecdsa"," (Elliptic Curve Digital Signature Algorithm) and ",[48,80,81],{},"ed25519"," (Edwards Curve Digital Signature Algorithm) keys already supported. But that ",[48,84,85],{},"-sk"," at the end adds the ability to verify the key with a FIDO/U2F device. \"SK\" here stands for \"security key\". ",[15,88,91],{"href":89,"rel":90},"https://www.openssh.com/txt/release-8.2",[],"OpenSSH 8.2"," added this key type to the supported keys it can generate, interacting with the hardware device to authenticate user presence before allowing the key to be used.",[12,94,95],{},"However, I still had a few things to do to be ready to use the new keys.",[31,97,99],{"id":98},"updating-openssh","Updating OpenSSH",[12,101,102,103,105],{},"My daily driver computer is a 2021 iMac running macOS Big Sur version 11.6. When I ran to it to generate this new key, I encountered a problem. Supposedly my version of SSH didn't support ",[48,104,85],{}," keys!",[12,107,108,109,112,113,116],{},"Now, your mileage may vary here, but I was able to update the version of SSH my Mac uses by default by first running ",[48,110,111],{},"brew install openssh",", which successfully installed OpenSSH 8.8. But when I ran ",[48,114,115],{},"ssh -V"," it still showed version 8.1. So how could I get the system to use the newly installed OpenSSH instead?",[12,118,119,120,123],{},"The easiest way I could think of to do that was to put the Homebrew version first in the $PATH variable. But where is that path? Luckily, I was able to find that (",[48,121,122],{},"/opt/homebrew/opt/openssh",") by running this command:",[12,125,126],{},[48,127,128],{},"brew --prefix openssh",[12,130,131],{},"Once I updated my $PATH variable to have that at the front, I got the desired outcome:",[133,134,139],"pre",{"className":135,"code":136,"language":137,"meta":138,"style":138},"language-bash shiki shiki-themes github-light","$  which ssh\n/opt/homebrew/opt/openssh/bin/ssh\n\n$ ssh -V\nOpenSSH_8.8p1, OpenSSL 1.1.1m  14 Dec 2021\n","bash","",[48,140,141,157,163,170,182],{"__ignoreMap":138},[142,143,146,150,154],"span",{"class":144,"line":145},"line",1,[142,147,149],{"class":148},"s7eDp","$",[142,151,153],{"class":152},"sYBdl","  which",[142,155,156],{"class":152}," ssh\n",[142,158,160],{"class":144,"line":159},2,[142,161,162],{"class":148},"/opt/homebrew/opt/openssh/bin/ssh\n",[142,164,166],{"class":144,"line":165},3,[142,167,169],{"emptyLinePlaceholder":168},true,"\n",[142,171,173,175,178],{"class":144,"line":172},4,[142,174,149],{"class":148},[142,176,177],{"class":152}," ssh",[142,179,181],{"class":180},"sYu0t"," -V\n",[142,183,185,188,191,194,197,200],{"class":144,"line":184},5,[142,186,187],{"class":148},"OpenSSH_8.8p1,",[142,189,190],{"class":152}," OpenSSL",[142,192,193],{"class":152}," 1.1.1m",[142,195,196],{"class":180},"  14",[142,198,199],{"class":152}," Dec",[142,201,202],{"class":180}," 2021\n",[31,204,206],{"id":205},"generating-the-key","Generating the key",[12,208,209,210,212],{},"Now that I was using the correct version of SSH, I was able to create my ",[48,211,50],{}," key by running:",[133,214,216],{"className":135,"code":215,"language":137,"meta":138,"style":138},"ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk\n",[48,217,218],{"__ignoreMap":138},[142,219,220,223,226,229,232],{"class":144,"line":145},[142,221,222],{"class":148},"ssh-keygen",[142,224,225],{"class":180}," -t",[142,227,228],{"class":152}," ecdsa-sk",[142,230,231],{"class":180}," -f",[142,233,234],{"class":152}," ~/.ssh/id_ecdsa_sk\n",[12,236,237,238,240,241,244],{},"Now, the specific device I have only supports ECDSA and not EdDSA, which is why I went with ",[48,239,50],{},". There also is an option to have the key reside ON the device itself (if supported by your hardware) with the ",[48,242,243],{},"-O resident"," flag like this:",[133,246,248],{"className":135,"code":247,"language":137,"meta":138,"style":138},"$ ssh-keygen -t ecdsa-sk -O resident -f ~/.ssh/id_ecdsa_sk\n\nEnter PIN for authenticator:\nYou may need to touch your authenticator (again) to authorize key generation.\nEnter passphrase (empty for no passphrase):\nEnter same passphrase again:\nYour identification has been saved in /Users/brendan/.ssh/id_ecdsa_sk\nYour public key has been saved in /Users/brendan/.ssh/id_ecdsa_sk.pub\n",[48,249,250,271,275,289,316,337,350,374],{"__ignoreMap":138},[142,251,252,254,257,259,261,264,267,269],{"class":144,"line":145},[142,253,149],{"class":148},[142,255,256],{"class":152}," ssh-keygen",[142,258,225],{"class":180},[142,260,228],{"class":152},[142,262,263],{"class":180}," -O",[142,265,266],{"class":152}," resident",[142,268,231],{"class":180},[142,270,234],{"class":152},[142,272,273],{"class":144,"line":159},[142,274,169],{"emptyLinePlaceholder":168},[142,276,277,280,283,286],{"class":144,"line":165},[142,278,279],{"class":148},"Enter",[142,281,282],{"class":152}," PIN",[142,284,285],{"class":152}," for",[142,287,288],{"class":152}," authenticator:\n",[142,290,291,294,297,300,303,306,309,312],{"class":144,"line":172},[142,292,293],{"class":148},"You",[142,295,296],{"class":152}," may",[142,298,299],{"class":152}," need",[142,301,302],{"class":152}," to",[142,304,305],{"class":152}," touch",[142,307,308],{"class":152}," your",[142,310,311],{"class":152}," authenticator",[142,313,315],{"class":314},"sgsFI"," (again) to authorize key generation.\n",[142,317,318,320,323,326,329,332,334],{"class":144,"line":184},[142,319,279],{"class":148},[142,321,322],{"class":152}," passphrase",[142,324,325],{"class":314}," (empty ",[142,327,328],{"class":152},"for",[142,330,331],{"class":152}," no",[142,333,322],{"class":152},[142,335,336],{"class":314},"):\n",[142,338,340,342,345,347],{"class":144,"line":339},6,[142,341,279],{"class":148},[142,343,344],{"class":152}," same",[142,346,322],{"class":152},[142,348,349],{"class":152}," again:\n",[142,351,353,356,359,362,365,368,371],{"class":144,"line":352},7,[142,354,355],{"class":148},"Your",[142,357,358],{"class":152}," identification",[142,360,361],{"class":152}," has",[142,363,364],{"class":152}," been",[142,366,367],{"class":152}," saved",[142,369,370],{"class":152}," in",[142,372,373],{"class":152}," /Users/brendan/.ssh/id_ecdsa_sk\n",[142,375,377,379,382,385,387,389,391,393],{"class":144,"line":376},8,[142,378,355],{"class":148},[142,380,381],{"class":152}," public",[142,383,384],{"class":152}," key",[142,386,361],{"class":152},[142,388,364],{"class":152},[142,390,367],{"class":152},[142,392,370],{"class":152},[142,394,395],{"class":152}," /Users/brendan/.ssh/id_ecdsa_sk.pub\n",[12,397,398,399,404],{},"Generating a resident key will make sharing this key with a new computer if and when that happens much easier. If you have a YubiKey like me, you can set the FIDO2 PIN using the ",[15,400,403],{"href":401,"rel":402},"https://www.yubico.com/support/download/yubikey-manager/",[],"YubiKey Manager"," software.",[31,406,408],{"id":407},"adding-the-key-to-gitlab","Adding the key to GitLab",[12,410,411,412,417,418,421],{},"Now that I had the complex parts covered, all that was left was to add the key to GitLab. I went to my ",[15,413,416],{"href":414,"rel":415},"https://gitlab.com/-/profile/keys",[],"SSH settings"," on GitLab.com and (bravely) deleted my old SSH key and added the ",[48,419,420],{},".pub"," public part of my key to my profile.",[12,423,424],{},"And it was that simple! Now every time I go to interact with GitLab.com, I'm prompted to confirm my presence by touching the YubiKey device attached to my computer:",[133,426,428],{"className":135,"code":427,"language":137,"meta":138,"style":138},"git clone git@gitlab.com:brendan/website.git\nCloning into 'website'...\nConfirm user presence for key ECDSA-SK SHA256:OZSZGwbnnbc...\n\ngit add .\ngit commit -m \"A new commit\"\ngit push\nConfirm user presence for key ECDSA-SK SHA256:OZSZGwbnnbc...\n",[48,429,430,441,452,473,477,487,500,507],{"__ignoreMap":138},[142,431,432,435,438],{"class":144,"line":145},[142,433,434],{"class":148},"git",[142,436,437],{"class":152}," clone",[142,439,440],{"class":152}," git@gitlab.com:brendan/website.git\n",[142,442,443,446,449],{"class":144,"line":159},[142,444,445],{"class":148},"Cloning",[142,447,448],{"class":152}," into",[142,450,451],{"class":152}," 'website'...\n",[142,453,454,457,460,463,465,467,470],{"class":144,"line":165},[142,455,456],{"class":148},"Confirm",[142,458,459],{"class":152}," user",[142,461,462],{"class":152}," presence",[142,464,285],{"class":152},[142,466,384],{"class":152},[142,468,469],{"class":152}," ECDSA-SK",[142,471,472],{"class":152}," SHA256:OZSZGwbnnbc...\n",[142,474,475],{"class":144,"line":172},[142,476,169],{"emptyLinePlaceholder":168},[142,478,479,481,484],{"class":144,"line":184},[142,480,434],{"class":148},[142,482,483],{"class":152}," add",[142,485,486],{"class":152}," .\n",[142,488,489,491,494,497],{"class":144,"line":339},[142,490,434],{"class":148},[142,492,493],{"class":152}," commit",[142,495,496],{"class":180}," -m",[142,498,499],{"class":152}," \"A new commit\"\n",[142,501,502,504],{"class":144,"line":352},[142,503,434],{"class":148},[142,505,506],{"class":152}," push\n",[142,508,509,511,513,515,517,519,521],{"class":144,"line":376},[142,510,456],{"class":148},[142,512,459],{"class":152},[142,514,462],{"class":152},[142,516,285],{"class":152},[142,518,384],{"class":152},[142,520,469],{"class":152},[142,522,472],{"class":152},[12,524,525],{},"That small but essential change gives me peace of mind that even if someone could somehow get my private SSH key, I would still be protected by having physical access restricted to my YubiKey.",[527,528,529],"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 pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}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 .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}",{"title":138,"searchDepth":159,"depth":159,"links":531},[532,536,537,538],{"id":33,"depth":159,"text":34,"children":533},[534],{"id":65,"depth":165,"text":535},"What are ecdsa-sk and ed25519-sk?",{"id":98,"depth":159,"text":99},{"id":205,"depth":159,"text":206},{"id":407,"depth":159,"text":408},"engineering","2022-03-03","Add a layer of security to SSH keys by restricting physical access to YubiKey.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667202/Blog/Hero%20Images/gitlabultimatesecurity.jpg",{},"/en-us/blog/how-to-protect-gitlab-connected-ssh-key-with-yubikey",{"title":5,"description":541,"ogTitle":5,"ogDescription":541,"noIndex":544,"ogImage":545,"ogUrl":549,"ogSiteName":550,"ogType":551,"canonicalUrls":549},"https://about.gitlab.com/blog/how-to-protect-gitlab-connected-ssh-key-with-yubikey","https://about.gitlab.com","article","how-to-protect-gitlab-connected-ssh-key-with-yubikey","en-us/blog/how-to-protect-gitlab-connected-ssh-key-with-yubikey",[555,556,557],"DevOps","security","tutorial","BlogPost","UCdxfUwZeiFmxDhNGa63Z3JFPIO1H7u0NoG5JhbaL7M",{"logo":561,"freeTrial":566,"sales":571,"login":576,"items":581,"search":908,"minimal":939,"duo":958,"switchNav":967,"pricingDeployment":978},{"config":562},{"href":563,"dataGaName":564,"dataGaLocation":565},"/","gitlab logo","header",{"text":567,"config":568},"Get free trial",{"href":569,"dataGaName":570,"dataGaLocation":565},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":572,"config":573},"Request a demo",{"href":574,"dataGaName":575,"dataGaLocation":565},"/sales/?contact-topic=request-demo","sales",{"text":577,"config":578},"Sign in",{"href":579,"dataGaName":580,"dataGaLocation":565},"https://gitlab.com/users/sign_in/","sign in",[582,611,711,716,830,886],{"text":583,"config":584,"menu":586},"Platform",{"dataNavLevelOne":585},"platform",{"type":587,"columns":588},"cards",[589,595,603],{"title":583,"description":590,"link":591},"The intelligent orchestration platform for DevSecOps",{"text":592,"config":593},"Explore our Platform",{"href":594,"dataGaName":585,"dataGaLocation":565},"/platform/",{"title":596,"description":597,"link":598},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":599,"config":600},"Meet GitLab Duo",{"href":601,"dataGaName":602,"dataGaLocation":565},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":604,"description":605,"link":606},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":607,"config":608},"Learn more",{"href":609,"dataGaName":610,"dataGaLocation":565},"/why-gitlab/","why gitlab",{"text":612,"left":168,"config":613,"menu":615},"Product",{"dataNavLevelOne":614},"solutions",{"type":616,"link":617,"columns":621,"feature":690},"lists",{"text":618,"config":619},"View all Solutions",{"href":620,"dataGaName":614,"dataGaLocation":565},"/solutions/",[622,646,669],{"title":623,"description":624,"link":625,"items":630},"Automation","CI/CD and automation to accelerate deployment",{"config":626},{"icon":627,"href":628,"dataGaName":629,"dataGaLocation":565},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[631,635,638,642],{"text":632,"config":633},"CI/CD",{"href":634,"dataGaLocation":565,"dataGaName":632},"/solutions/continuous-integration/",{"text":596,"config":636},{"href":601,"dataGaLocation":565,"dataGaName":637},"gitlab duo agent platform - product menu",{"text":639,"config":640},"Source Code Management",{"href":641,"dataGaLocation":565,"dataGaName":639},"/solutions/source-code-management/",{"text":643,"config":644},"Automated Software Delivery",{"href":628,"dataGaLocation":565,"dataGaName":645},"Automated software delivery",{"title":647,"description":648,"link":649,"items":654},"Security","Deliver code faster without compromising security",{"config":650},{"href":651,"dataGaName":652,"dataGaLocation":565,"icon":653},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[655,659,664],{"text":656,"config":657},"Application Security Testing",{"href":651,"dataGaName":658,"dataGaLocation":565},"Application security testing",{"text":660,"config":661},"Software Supply Chain Security",{"href":662,"dataGaLocation":565,"dataGaName":663},"/solutions/supply-chain/","Software supply chain security",{"text":665,"config":666},"Software Compliance",{"href":667,"dataGaName":668,"dataGaLocation":565},"/solutions/software-compliance/","software compliance",{"title":670,"link":671,"items":676},"Measurement",{"config":672},{"icon":673,"href":674,"dataGaName":675,"dataGaLocation":565},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[677,681,685],{"text":678,"config":679},"Visibility & Measurement",{"href":674,"dataGaLocation":565,"dataGaName":680},"Visibility and Measurement",{"text":682,"config":683},"Value Stream Management",{"href":684,"dataGaLocation":565,"dataGaName":682},"/solutions/value-stream-management/",{"text":686,"config":687},"Analytics & Insights",{"href":688,"dataGaLocation":565,"dataGaName":689},"/solutions/analytics-and-insights/","Analytics and insights",{"title":691,"type":616,"items":692},"GitLab for",[693,699,705],{"text":694,"config":695},"Enterprise",{"icon":696,"href":697,"dataGaLocation":565,"dataGaName":698},"Building","/enterprise/","enterprise",{"text":700,"config":701},"Small Business",{"icon":702,"href":703,"dataGaLocation":565,"dataGaName":704},"Work","/small-business/","small business",{"text":706,"config":707},"Public Sector",{"icon":708,"href":709,"dataGaLocation":565,"dataGaName":710},"Organization","/solutions/public-sector/","public sector",{"text":712,"config":713},"Pricing",{"href":714,"dataGaName":715,"dataGaLocation":565,"dataNavLevelOne":715},"/pricing/","pricing",{"text":717,"config":718,"menu":720},"Resources",{"dataNavLevelOne":719},"resources",{"type":616,"link":721,"columns":725,"feature":819},{"text":722,"config":723},"View all resources",{"href":724,"dataGaName":719,"dataGaLocation":565},"/resources/",[726,759,786],{"title":727,"items":728},"Getting started",[729,734,739,744,749,754],{"text":730,"config":731},"Install",{"href":732,"dataGaName":733,"dataGaLocation":565},"/install/","install",{"text":735,"config":736},"Quick start guides",{"href":737,"dataGaName":738,"dataGaLocation":565},"/get-started/","quick setup checklists",{"text":740,"config":741},"Learn",{"href":742,"dataGaLocation":565,"dataGaName":743},"https://university.gitlab.com/","learn",{"text":745,"config":746},"Product documentation",{"href":747,"dataGaName":748,"dataGaLocation":565},"https://docs.gitlab.com/","product documentation",{"text":750,"config":751},"Best practice videos",{"href":752,"dataGaName":753,"dataGaLocation":565},"/getting-started-videos/","best practice videos",{"text":755,"config":756},"Integrations",{"href":757,"dataGaName":758,"dataGaLocation":565},"/integrations/","integrations",{"title":760,"items":761},"Discover",[762,767,772,777,781],{"text":763,"config":764},"Customer success stories",{"href":765,"dataGaName":766,"dataGaLocation":565},"/customers/","customer success stories",{"text":768,"config":769},"Blog",{"href":770,"dataGaName":771,"dataGaLocation":565},"/blog/","blog",{"text":773,"config":774},"Demo Hub",{"href":775,"dataGaName":776,"dataGaLocation":565},"/demo-hub/","demo hub",{"text":778,"config":779},"The Source",{"href":780,"dataGaName":771,"dataGaLocation":565},"/the-source/",{"text":782,"config":783},"Remote",{"href":784,"dataGaName":785,"dataGaLocation":565},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":787,"items":788},"Connect",[789,794,799,804,809,814],{"text":790,"config":791},"GitLab Services",{"href":792,"dataGaName":793,"dataGaLocation":565},"/services/","services",{"text":795,"config":796},"Contribute",{"href":797,"dataGaName":798,"dataGaLocation":565},"https://contributors.gitlab.com","contribute",{"text":800,"config":801},"Community",{"href":802,"dataGaName":803,"dataGaLocation":565},"/community/","community",{"text":805,"config":806},"Forum",{"href":807,"dataGaName":808,"dataGaLocation":565},"https://forum.gitlab.com/","forum",{"text":810,"config":811},"Events",{"href":812,"dataGaName":813,"dataGaLocation":565},"/events/","events",{"text":815,"config":816},"Partners",{"href":817,"dataGaName":818,"dataGaLocation":565},"/partners/","partners",{"config":820,"title":823,"text":824,"link":825},{"background":821,"textColor":822},"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":826,"config":827},"Read the latest",{"href":828,"dataGaName":829,"dataGaLocation":565},"/whats-new/","whats new",{"text":831,"config":832,"menu":834},"Company",{"dataNavLevelOne":833},"company",{"type":616,"columns":835},[836],{"items":837},[838,843,849,851,856,861,866,871,876,881],{"text":839,"config":840},"About",{"href":841,"dataGaName":842,"dataGaLocation":565},"/company/","about",{"text":844,"config":845,"footerGa":848},"Jobs",{"href":846,"dataGaName":847,"dataGaLocation":565},"/jobs/","jobs",{"dataGaName":847},{"text":810,"config":850},{"href":812,"dataGaName":813,"dataGaLocation":565},{"text":852,"config":853},"Leadership",{"href":854,"dataGaName":855,"dataGaLocation":565},"/company/team/e-group/","leadership",{"text":857,"config":858},"Handbook",{"href":859,"dataGaName":860,"dataGaLocation":565},"https://handbook.gitlab.com/","handbook",{"text":862,"config":863},"Investor relations",{"href":864,"dataGaName":865,"dataGaLocation":565},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":867,"config":868},"Trust Center",{"href":869,"dataGaName":870,"dataGaLocation":565},"/security/","trust center",{"text":872,"config":873},"AI Transparency Center",{"href":874,"dataGaName":875,"dataGaLocation":565},"/ai-transparency-center/","ai transparency center",{"text":877,"config":878},"Newsletter",{"href":879,"dataGaName":880,"dataGaLocation":565},"/company/contact/#contact-forms","newsletter",{"text":882,"config":883},"Press",{"href":884,"dataGaName":885,"dataGaLocation":565},"/press/","press",{"text":887,"config":888,"menu":889},"Contact us",{"dataNavLevelOne":833},{"type":616,"columns":890},[891],{"items":892},[893,898,903],{"text":894,"config":895},"Talk to sales",{"href":896,"dataGaName":897,"dataGaLocation":565},"/sales/","talk to sales",{"text":899,"config":900},"Support portal",{"href":901,"dataGaName":902,"dataGaLocation":565},"https://support.gitlab.com/hc/en-us","support portal",{"text":904,"config":905},"Customer portal",{"href":906,"dataGaName":907,"dataGaLocation":565},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":909,"login":910,"suggestions":917},"Close",{"text":911,"link":912},"To search repositories and projects, login to",{"text":913,"config":914},"gitlab.com",{"href":579,"dataGaName":915,"dataGaLocation":916},"search login","search",{"text":918,"default":919},"Suggestions",[920,922,926,928,932,936],{"text":596,"config":921},{"href":601,"dataGaName":596,"dataGaLocation":916},{"text":923,"config":924},"Code Suggestions (AI)",{"href":925,"dataGaName":923,"dataGaLocation":916},"/solutions/code-suggestions/",{"text":632,"config":927},{"href":634,"dataGaName":632,"dataGaLocation":916},{"text":929,"config":930},"GitLab on AWS",{"href":931,"dataGaName":929,"dataGaLocation":916},"/partners/technology-partners/aws/",{"text":933,"config":934},"GitLab on Google Cloud",{"href":935,"dataGaName":933,"dataGaLocation":916},"/partners/technology-partners/google-cloud-platform/",{"text":937,"config":938},"Why GitLab?",{"href":609,"dataGaName":937,"dataGaLocation":916},{"freeTrial":940,"mobileIcon":945,"desktopIcon":950,"secondaryButton":953},{"text":941,"config":942},"Start free trial",{"href":943,"dataGaName":570,"dataGaLocation":944},"https://gitlab.com/-/trials/new/","nav",{"altText":946,"config":947},"Gitlab Icon",{"src":948,"dataGaName":949,"dataGaLocation":944},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":946,"config":951},{"src":952,"dataGaName":949,"dataGaLocation":944},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":954,"config":955},"Get Started",{"href":956,"dataGaName":957,"dataGaLocation":944},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":959,"mobileIcon":963,"desktopIcon":965},{"text":960,"config":961},"Learn more about GitLab Duo",{"href":601,"dataGaName":962,"dataGaLocation":944},"gitlab duo",{"altText":946,"config":964},{"src":948,"dataGaName":949,"dataGaLocation":944},{"altText":946,"config":966},{"src":952,"dataGaName":949,"dataGaLocation":944},{"button":968,"mobileIcon":973,"desktopIcon":975},{"text":969,"config":970},"/switch",{"href":971,"dataGaName":972,"dataGaLocation":944},"#contact","switch",{"altText":946,"config":974},{"src":948,"dataGaName":949,"dataGaLocation":944},{"altText":946,"config":976},{"src":977,"dataGaName":949,"dataGaLocation":944},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":979,"mobileIcon":984,"desktopIcon":986},{"text":980,"config":981},"Back to pricing",{"href":714,"dataGaName":982,"dataGaLocation":944,"icon":983},"back to pricing","GoBack",{"altText":946,"config":985},{"src":948,"dataGaName":949,"dataGaLocation":944},{"altText":946,"config":987},{"src":952,"dataGaName":949,"dataGaLocation":944},{"title":989,"titleMobile":990,"button":991,"config":996},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":607,"config":992},{"href":993,"dataGaName":994,"dataGaLocation":995},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":997,"disabled":544},"release",{"data":999},{"text":1000,"source":1001,"edit":1007,"contribute":1012,"config":1017,"items":1022,"minimal":1231},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1002,"config":1003},"View page source",{"href":1004,"dataGaName":1005,"dataGaLocation":1006},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1008,"config":1009},"Edit this page",{"href":1010,"dataGaName":1011,"dataGaLocation":1006},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1013,"config":1014},"Please contribute",{"href":1015,"dataGaName":1016,"dataGaLocation":1006},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1018,"facebook":1019,"youtube":1020,"linkedin":1021},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1023,1070,1123,1167,1199],{"title":712,"links":1024,"subMenu":1039},[1025,1029,1034],{"text":1026,"config":1027},"View plans",{"href":714,"dataGaName":1028,"dataGaLocation":1006},"view plans",{"text":1030,"config":1031},"Why Premium?",{"href":1032,"dataGaName":1033,"dataGaLocation":1006},"/pricing/premium/","why premium",{"text":1035,"config":1036},"Why Ultimate?",{"href":1037,"dataGaName":1038,"dataGaLocation":1006},"/pricing/ultimate/","why ultimate",[1040],{"title":1041,"links":1042},"Contact Us",[1043,1046,1048,1050,1055,1060,1065],{"text":1044,"config":1045},"Contact sales",{"href":896,"dataGaName":575,"dataGaLocation":1006},{"text":899,"config":1047},{"href":901,"dataGaName":902,"dataGaLocation":1006},{"text":904,"config":1049},{"href":906,"dataGaName":907,"dataGaLocation":1006},{"text":1051,"config":1052},"Status",{"href":1053,"dataGaName":1054,"dataGaLocation":1006},"https://status.gitlab.com/","status",{"text":1056,"config":1057},"Terms of use",{"href":1058,"dataGaName":1059,"dataGaLocation":1006},"/terms/","terms of use",{"text":1061,"config":1062},"Privacy statement",{"href":1063,"dataGaName":1064,"dataGaLocation":1006},"/privacy/","privacy statement",{"text":1066,"config":1067},"Cookie preferences",{"dataGaName":1068,"dataGaLocation":1006,"id":1069,"isOneTrustButton":168},"cookie preferences","ot-sdk-btn",{"title":612,"links":1071,"subMenu":1080},[1072,1076],{"text":1073,"config":1074},"DevSecOps platform",{"href":594,"dataGaName":1075,"dataGaLocation":1006},"devsecops platform",{"text":1077,"config":1078},"AI-Assisted Development",{"href":601,"dataGaName":1079,"dataGaLocation":1006},"ai-assisted development",[1081],{"title":1082,"links":1083},"Topics",[1084,1089,1094,1098,1103,1108,1113,1118],{"text":1085,"config":1086},"CICD",{"href":1087,"dataGaName":1088,"dataGaLocation":1006},"/topics/ci-cd/","cicd",{"text":1090,"config":1091},"GitOps",{"href":1092,"dataGaName":1093,"dataGaLocation":1006},"/topics/gitops/","gitops",{"text":555,"config":1095},{"href":1096,"dataGaName":1097,"dataGaLocation":1006},"/topics/devops/","devops",{"text":1099,"config":1100},"Version Control",{"href":1101,"dataGaName":1102,"dataGaLocation":1006},"/topics/version-control/","version control",{"text":1104,"config":1105},"DevSecOps",{"href":1106,"dataGaName":1107,"dataGaLocation":1006},"/topics/devsecops/","devsecops",{"text":1109,"config":1110},"Cloud Native",{"href":1111,"dataGaName":1112,"dataGaLocation":1006},"/topics/cloud-native/","cloud native",{"text":1114,"config":1115},"AI for Coding",{"href":1116,"dataGaName":1117,"dataGaLocation":1006},"/topics/devops/ai-for-coding/","ai for coding",{"text":1119,"config":1120},"Agentic AI",{"href":1121,"dataGaName":1122,"dataGaLocation":1006},"/topics/agentic-ai/","agentic ai",{"title":1124,"links":1125},"Solutions",[1126,1128,1130,1135,1139,1142,1146,1149,1151,1154,1157,1162],{"text":656,"config":1127},{"href":651,"dataGaName":656,"dataGaLocation":1006},{"text":645,"config":1129},{"href":628,"dataGaName":629,"dataGaLocation":1006},{"text":1131,"config":1132},"Agile development",{"href":1133,"dataGaName":1134,"dataGaLocation":1006},"/solutions/agile-delivery/","agile delivery",{"text":1136,"config":1137},"SCM",{"href":641,"dataGaName":1138,"dataGaLocation":1006},"source code management",{"text":1085,"config":1140},{"href":634,"dataGaName":1141,"dataGaLocation":1006},"continuous integration & delivery",{"text":1143,"config":1144},"Value stream management",{"href":684,"dataGaName":1145,"dataGaLocation":1006},"value stream management",{"text":1090,"config":1147},{"href":1148,"dataGaName":1093,"dataGaLocation":1006},"/solutions/gitops/",{"text":694,"config":1150},{"href":697,"dataGaName":698,"dataGaLocation":1006},{"text":1152,"config":1153},"Small business",{"href":703,"dataGaName":704,"dataGaLocation":1006},{"text":1155,"config":1156},"Public sector",{"href":709,"dataGaName":710,"dataGaLocation":1006},{"text":1158,"config":1159},"Education",{"href":1160,"dataGaName":1161,"dataGaLocation":1006},"/solutions/education/","education",{"text":1163,"config":1164},"Financial services",{"href":1165,"dataGaName":1166,"dataGaLocation":1006},"/solutions/finance/","financial services",{"title":717,"links":1168},[1169,1171,1173,1175,1178,1180,1183,1185,1187,1189,1191,1193,1195,1197],{"text":730,"config":1170},{"href":732,"dataGaName":733,"dataGaLocation":1006},{"text":735,"config":1172},{"href":737,"dataGaName":738,"dataGaLocation":1006},{"text":740,"config":1174},{"href":742,"dataGaName":743,"dataGaLocation":1006},{"text":745,"config":1176},{"href":747,"dataGaName":1177,"dataGaLocation":1006},"docs",{"text":768,"config":1179},{"href":770,"dataGaName":771,"dataGaLocation":1006},{"text":1181,"config":1182},"What's new",{"href":828,"dataGaName":829,"dataGaLocation":1006},{"text":763,"config":1184},{"href":765,"dataGaName":766,"dataGaLocation":1006},{"text":782,"config":1186},{"href":784,"dataGaName":785,"dataGaLocation":1006},{"text":790,"config":1188},{"href":792,"dataGaName":793,"dataGaLocation":1006},{"text":795,"config":1190},{"href":797,"dataGaName":798,"dataGaLocation":1006},{"text":800,"config":1192},{"href":802,"dataGaName":803,"dataGaLocation":1006},{"text":805,"config":1194},{"href":807,"dataGaName":808,"dataGaLocation":1006},{"text":810,"config":1196},{"href":812,"dataGaName":813,"dataGaLocation":1006},{"text":815,"config":1198},{"href":817,"dataGaName":818,"dataGaLocation":1006},{"title":831,"links":1200},[1201,1203,1205,1207,1209,1211,1215,1220,1222,1224,1226],{"text":839,"config":1202},{"href":841,"dataGaName":833,"dataGaLocation":1006},{"text":844,"config":1204},{"href":846,"dataGaName":847,"dataGaLocation":1006},{"text":852,"config":1206},{"href":854,"dataGaName":855,"dataGaLocation":1006},{"text":857,"config":1208},{"href":859,"dataGaName":860,"dataGaLocation":1006},{"text":862,"config":1210},{"href":864,"dataGaName":865,"dataGaLocation":1006},{"text":1212,"config":1213},"Sustainability",{"href":1214,"dataGaName":1212,"dataGaLocation":1006},"/sustainability/",{"text":1216,"config":1217},"Diversity, inclusion and belonging (DIB)",{"href":1218,"dataGaName":1219,"dataGaLocation":1006},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":867,"config":1221},{"href":869,"dataGaName":870,"dataGaLocation":1006},{"text":877,"config":1223},{"href":879,"dataGaName":880,"dataGaLocation":1006},{"text":882,"config":1225},{"href":884,"dataGaName":885,"dataGaLocation":1006},{"text":1227,"config":1228},"Modern Slavery Transparency Statement",{"href":1229,"dataGaName":1230,"dataGaLocation":1006},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1232},[1233,1236,1239],{"text":1234,"config":1235},"Terms",{"href":1058,"dataGaName":1059,"dataGaLocation":1006},{"text":1237,"config":1238},"Cookies",{"dataGaName":1068,"dataGaLocation":1006,"id":1069,"isOneTrustButton":168},{"text":1240,"config":1241},"Privacy",{"href":1063,"dataGaName":1064,"dataGaLocation":1006},[1243],{"id":1244,"title":1245,"body":543,"config":1246,"content":1248,"description":543,"extension":1251,"meta":1252,"navigation":168,"path":1253,"seo":1254,"stem":1255,"__hash__":1256},"blogAuthors/en-us/blog/authors/brendan-oleary.yml","Brendan Oleary",{"template":1247},"BlogAuthor",{"name":7,"config":1249},{"headshot":138,"ctfId":1250},"brendan","yml",{},"/en-us/blog/authors/brendan-oleary",{},"en-us/blog/authors/brendan-oleary","IkXVLft77WlFK-Vgo210ZM3Io_PCcrXnYzkBCzx153k",[1258,1267,1275],{"title":1259,"description":1260,"heroImage":1261,"category":539,"date":1262,"authors":1263,"slug":1266,"externalUrl":543},"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",[1264,1265],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1268,"description":1269,"heroImage":1270,"category":539,"date":1271,"authors":1272,"slug":1274,"externalUrl":543},"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",[1273],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1276,"description":1277,"heroImage":1278,"category":539,"date":1279,"authors":1280,"slug":1282,"externalUrl":543},"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",[1281],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1284},[1285,1299,1311,1322],{"id":1286,"categories":1287,"header":1289,"text":1290,"button":1291,"image":1296},"ai-modernization",[1288],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1292,"config":1293},"Get your AI maturity score",{"href":1294,"dataGaName":1295,"dataGaLocation":771},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1297},{"src":1298},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1300,"categories":1301,"header":1303,"text":1290,"button":1304,"image":1308},"devops-modernization",[1302,1107],"product","Are you just managing tools or shipping innovation?",{"text":1305,"config":1306},"Get your DevOps maturity score",{"href":1307,"dataGaName":1295,"dataGaLocation":771},"/assessments/devops-modernization-assessment/",{"config":1309},{"src":1310},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1312,"categories":1313,"header":1314,"text":1290,"button":1315,"image":1319},"security-modernization",[556],"Are you trading speed for security?",{"text":1316,"config":1317},"Get your security maturity score",{"href":1318,"dataGaName":1295,"dataGaLocation":771},"/assessments/security-modernization-assessment/",{"config":1320},{"src":1321},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1323,"paths":1324,"header":1327,"text":1328,"button":1329,"image":1334},"github-azure-migration",[1325,1326],"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":1330,"config":1331},"See how GitLab compares to GitHub",{"href":1332,"dataGaName":1333,"dataGaLocation":771},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1335},{"src":1310},{"header":1337,"blurb":1338,"button":1339,"secondaryButton":1344},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1340,"config":1341},"Get your free trial",{"href":1342,"dataGaName":570,"dataGaLocation":1343},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1044,"config":1345},{"href":896,"dataGaName":575,"dataGaLocation":1343},1786803735037]