gitlab two-factor authentication 完整避坑指南开启之后开发工作流怎么调才不炸两个星期前我们组一个开发小哥的 GitLab 账号被撞库了攻击者拿到密码之后直接把私有仓库克隆了个遍还在仓库里插了挖矿脚本的 commit。万幸的是他还没开双因素认证账号一旦绑定 two-factor authentication就算密码泄露几天攻击者大概率也进不来。从那天起我把项目组所有成员账号都强推了 2FA折腾完 Web 端登录之后又引出 SSH、HTTPS 拉代码、CI/CD Runner、IDE 提交等一系列连锁问题。这篇文章就是基于我这次“全量开通 GitLab two-factor authentication”的实操过程写出来的。内容覆盖 2FA 原理、启用流程、认证工具选型、开启后开发工作流的适配以及我在 Docker 自建 GitLab 里踩过的恢复坑。文中的步骤和代码都是我在真实环境里跑过的适合刚把 2FA 提上日程的团队也适合被 2FA 锁在门外正在找恢复方法的同学。1. 为什么 GitLab 必须开双因素认证1.1 代码仓库失守的代价聊 2FA 之前先说结论GitLab 账号本质上是你整个软件供应链的钥匙。里面不只有源码还有 CI/CD 流水线配置、部署密钥、容器镜像仓库的推送权限、环境变量里的数据库密码和云服务密钥。一个账号被拿轻则私有代码泄露重则攻击者通过修改.gitlab-ci.yml实现供应链投毒把恶意代码直接送进生产环境。GitLab 官方也很清楚这个风险所以在账号安全设置里把 two-factor authentication 直接放在显眼位置。安全事故统计里“凭证泄露 弱密码复用”始终占第一梯队。密码可以靠撞库拿到但第二因素手机里的动态验证码、恢复码、硬件 key是攻击者没法远程偷走的东西。1.2 双因素认证到底验证了什么双因素认证的核心是“三样东西”你知道的密码、你拥有的手机/硬件 key、你本身的指纹/人脸。GitLab 的 2FA 走的是 TOTPTime-based One-Time Password协议也就是基于时间的动态口令——认证器和服务器各自持有一个共享密钥以当前 Unix 时间戳为输入每 30 秒生成一组 6 位数验证码。两端算法一致、时间一致验证码就一致所以常见的验证失败原因基本都是手机时间与服务器时间偏差过大。GitLab 启用 2FA 后并非只保护网页登录它实际防守的入口很广Web 界面登录、登出、密码重置使用账号密码通过 HTTPS 方式执行 Git 操作git fetch、git push通过 GraphQL API 或 REST API 以账号密码换取 token管理员后台的关键操作二次确认这条必须提前理解GitLab 的 2FA 不直接拦截 SSH 协议因为 SSH 走的是公钥认证包里根本没有密码。很多人开完 2FA 后发现 SSH 照样能拉代码就误以为 2FA 没生效其实是机制不同。1.3 一个被忽略的“账户锁定”场景开了 2FA 之后密码泄露的生存窗口会大大缩短但前提是你没有把恢复码落在攻击者手里。GitLab 在绑定 2FA 时会一次性生成一串恢复码recovery codes每个恢复码只能使用一次用于手机丢失、认证器数据被清空时重新登录。我见过太多人把恢复码截图丢在聊天软件里或者干脆顺手复制到桌面 txt 就忘了删。还有个细节GitLab 允许同时启用 TOTP 应用和 WebAuthn 硬件安全密钥两者可以并存。恢复码是最后的逃生通道这些手段不冲突建议有条件都开。硬件 key 的好处是防钓鱼能力比普通 TOTP 强得多但很多团队嫌成本高至少把 TOTP 恢复码做扎实。2. 在 GitLab 上启用双因素认证的完整流程2.1 启用前的必要准备先别急着点“开启”准备工作做足能省掉后面一大半的麻烦。第一步是确认账号邮箱可访问因为开启 2FA 以及后续找回流程都会往邮箱发通知。第二步是准备一个支持 TOTP 的认证工具手机上装 Google Authenticator、Microsoft Authenticator、Authy、1Password 都行或者浏览器装 Bitwarden、KeePassXC 这类扩展。我个人建议优先用支持云同步的认证器1Password、Bitwarden因为换手机时不会把所有种子全丢。Google Authenticator 的换机迁移要手动扫码很容易翻车后面我会单独说这个问题。注意提前在 GitLab 里看一眼自己有哪些访问凭证。SSH key 不受影响但如果你平时是用 HTTPS 账号密码拉代码的开完 2FA 之后密码方式会立刻失效需要改用 Personal Access Token这条很多人没注意结果当场卡死。2.2 一步步操作绑定 TOTP 验证器以 GitLab 15.x/16.x 社区版界面为例SaaS 版一样路径是右上角头像 →Preferences偏好设置→ 左侧Account账号→ 找到Two-Factor Authentication区块点击Enable Two-Factor Authentication。这时候页面会展示一个大大的二维码旁边是一串可以手动输入的 base32 密钥通常以otpauth://totp/gitlab:yournamedomain?secretXXX格式展示。在认证器里扫码或者手动输入密钥认证器就会开始滚动生成 6 位动态码。GitLab 出于安全考虑要求你连续输入两次动态码来确认你确实持有这个验证器。第一次验证码通过后页面会立刻显示恢复码清单同时要求输入第二次验证码完成绑定。这里要特别提醒别急着把恢复码关了先做三件事把恢复码抄在纸质笔记本上至少留一份不联网的备份用 Bitwarden 或者加密笔记里存一份电子版「不要」把恢复码截图发到聊天软件GitLab 的恢复码清单只在绑定那一刻完整展示一次之后不会给你看全文恢复码一般给 10 个每个只能用一次格式是 16 位乱码字符。用掉一个之后剩余数量可以在 2FA 设置页看到但不能反查明文。2.3 开启后马上要做的验证第一次开启 2FA 成功后先不要无脑高兴退出账号重新走一遍登录流程用 TOTP 动态码登录一次确认整个链路通了。登录时页面会先要求输入用户名密码下一步再要求输入 6 位验证码。中间有个可选勾选“Trust this device”信任此设备信任之后这台设备 30 天内再登录就不用重复输验证码。接着要比较坑的是GitLab 不会自动把你“已登录”状态剔除所以原会话仍然是有效的。如果你是在一台已经登录的机器上开的 2FA账户安全状态实际上还是旧会话要彻底安全必须主动点 Log out清掉所有旧会话。做完登录验证再验证恢复码。方法简单手机飞行模式模拟丢失设备场景用恢复码登录一次。这一步不用真的把数据清掉只要确认恢复码能登录即可。我用过 2FA 这么久最大的感受是恢复码这东西 99% 的时间用不上但一旦手机摔了、换机了它就是唯一救命的钥匙。3. 认证应用与浏览器扩展的选型对比3.1 主流认证工具实测体验GitLab 的提示语里有一句常见描述enter the code from your two-factor authentication app or browser extension。很多人纠结到底用 App 还是浏览器扩展我两种都长期用过直接给结论Google Authenticator老牌、简单、离线可用但它不支持多设备同步。换机迁移必须旧手机一个个扫码导出账号多了非常痛苦。Microsoft Authenticator支持云备份界面对多账号管理比 Google 的舒服一点GitLab 也能正常扫。Authy支持多设备同步但最近口碑有点下滑备份机制也有过争议。不推荐新用户上车。1Password / Bitwarden本质是密码管理器附带 TOTP 功能浏览器插件能自动检测 6 位码输入框并自动填充。团队里如果本来就在用密码管理器用它的 2FA 功能最顺滑我目前的主力方案就是这个。浏览器扩展如 Bitwarden 扩展、KeePassXC 浏览器集成优势是自动填充极度丝滑不用掏手机。缺点是依赖浏览器环境和扩展数据同步如果浏览器多账号隔离、或者开无痕模式要注意扩展是否自动解锁。3.2 多账号多 GitLab 实例怎么管理开发同学手里一般不止一个 GitLab 账号公司自建 GitLab、SaaS 版、客户方的 GitLab、可能还有 GitLab.com 上个人的私有仓库。每个账号的 2FA seed 都不同如果都绑在同一个认证器里账号一多会分不清哪个码对应哪个 GitLab。我的做法是给每个 GitLab 实例的账号在认证器里单独命名命名规则用GitLab-Prod-公司、GitLab-Personal、GitLab-CustomerA这种格式。扫码之后一定要立刻在认证器里顺便编辑条目名称否则默认名称可能只是邮箱前缀多个账号撞在一块完全分不清。如果用的是 Bitwarden 或者 1PasswordTOTP 种子直接存在对应登录条目里自动填充时会自动填充正确账号的验证码不需要记条目名体验最好。3.3 换手机与数据迁移的避坑建议这条非常实用务必看完。用 Google Authenticator 的老用户换手机时最常见的崩溃现场是新手机扫码绑定发现账号列表是一片空白旧手机早已被重置。Google Authenticator 的官方“转移账号”功能是用二维码把旧手机里的账号逐个导出就算有导出二维码也需要旧手机还能用。所以我的建议是能选支持云同步的认证器就尽量选支持云同步的在 GitLab 的恢复码还没用完的情况下把恢复码留好等新手机重新扫码绑定 GitLab 2FA 后旧恢复码自动作废新恢复码会重新生成如果所有认证器的 seed 都丢了、恢复码也没了那就只剩管理员后台强解一条路第 5 章有命令换完手机重新绑定后记得在 GitLab 的 2FA 设置页里重新下载并保存新的恢复码旧的恢复码在换绑成功后就没用了。4. 开启 2FA 后开发工作流的连锁适配4.1 SSH 方式基本不受影响但要给 key 上锁GitLab 的 2FA 属于“Web 登录会话侧的验证”SSH 协议走的是公钥认证不涉及密码和 TOTP。所以平时用 SSH 方式git fetch/push的人开 2FA 之后基本无感。这一点既是便利也是风险SSH key 一旦被拷走就等于拿到了仓库的“长期免密通行证”。我的建议是给本地 SSH key 加上 passphrase用ssh-keygen -t ed25519 -C your_email生成时输入口令。配合ssh-agent后只需要每次输入一次口令后续无需重复输入。这样哪怕 SSH private key 被偷没有 passphrase 也用不了。4.2 HTTPS 方式账号密码当场失效必须改用 Personal Access Token开 2FA 最明显的转折点就在这里。之前用 HTTPS 账号密码拉代码的人开完 2FA 之后再用密码会直接报HTTP Basic: Access denied。GitLab 要求所有 HTTPS 方式的 Git 操作改用 Personal Access TokenPAT作为密码。创建路径右上角头像 →Preferences→Access Tokens→ 填名称、选有效期、勾选read_repository和write_repository权限生成后复制 token。这个 token 只显示一次类似恢复码的性质关掉页面就再也看不到明文。拿到 token 后在命令行里这样用git clone https://oauth2:YOUR_PERSONAL_ACCESS_TOKENgitlab.example.com/group/project.git或者更稳妥的做法是配置 Git 凭据管理器把 token 存进本机凭据存储不用每次写 URLgit config --global credential.helper store但store是明文存 token不推荐用在共享机器上。Linux 下推荐libsecretmacOS 下用系统钥匙串Windows 下用 Git Credential Manager。注意创建 PAT 时权限别贪多只需要read_repository就坚决不给write_repository。生产环境的 CI/CD 里用的 token 权限要更保守最好用项目级的 deploy token而不是个人 PAT。4.3 IDE 提交PyCharm、VS Code 与 IntelliJ 的配置调整热词里有人搜“pycharm提交到gitlab”正好说一下。PyCharm 里的 Git 集成有两种方式连 GitLabSSH 或 HTTPS。开启 2FA 后如果你之前用的是 HTTPS 密码需要换成 Personal Access TokenPyCharm 操作路径File → Settings → Version Control → Git → 选中 remote 地址。如果你是 HTTPS URL在 Credentials 下拉里选择“Use credential helper”并在首次 push 时输入 GitLab 用户名和 PAT不是账号密码。如果你是 SSH URL则在 SSH executable 里选Native用本机 ssh-agent 管理私钥即可。VS Code 和 IntelliJ 思路一样要么用 SSH key要么在 credential helper 里填usernamePAT。代码里不要写 tokenIDE 的凭据管理器会自动保存。4.4 CI/CD 流水线与 Runner 注册的调整开启 2FA 后 CI/CD 这边有几个容易踩坑的点。第一如果项目中已经注册过 GitLab Runnerrunner 用的是项目里的registration_token和 runner 自己的authentication_token注册的这些 token 和注册过程并不过 2FA所以现有 runner 不会受影响。第二如果你想在 Web 页面“新建 Runner”或者通过界面查看 runner 的 registration token这些操作属于“管理范围的高危操作”GitLab 在安全策略上要求管理员账号执行有些场景会要求二次验证。如果你的 runner token 需要轮换提前在项目设置 →CI/CD→Runners里处理把旧 token 撤销再重新注册。第三流水线里如果要调用 GitLab API用CI_JOB_TOKEN比在 CI 变量里硬编码 PAT 安全得多。系统预置的CI_JOB_TOKEN在gitlab-ci.yml里直接可用deploy_job: stage: deploy script: - curl --header PRIVATE-TOKEN: $CI_JOB_TOKEN https://gitlab.example.com/api/v4/projects这样既不需要在 CI 变量里维护 PAT也避免了 2FA 环境下 token 过期无人维护的问题。4.5 Docker 部署自建 GitLab 的管理员恢复操作搜热词时发现“docker安装gitlab”相关的问题不少如果是 Docker 自建的 GitLab管理员碰到的 2FA 恢复问题比 SaaS 更棘手因为在 Web 上丢了恢复码你是没法“找官方客服”的只能进容器里操作。这里给一个我实测可用的命令docker exec -it gitlab gitlab-rails runner user User.find_by_username(your_username) user.otp_required_for_login false user.save! puts 2FA disabled 执行前先确认容器名是gitlab如果容器名不一样换成你自己的。这条命令的作用是把目标用户的otp_required_for_login字段设为 false等用户下次登录时就能直接绕过 2FA。同时建议把该用户的otp_secret清除彻底移除绑定的验证器docker exec -it gitlab gitlab-rails runner user User.find_by_username(your_username) user.otp_required_for_login false user.otp_secret nil user.save! 跑完字段更新后用户重新登录再绑定一个新的 2FA 即可。这个操作只适合管理员处理“忘了一切凭证”的极限场景平时尽量不要用脚本去动 2FA 字段否则等于给绕过开了一扇门。5. 常见问题与排查技巧实录5.1 恢复码丢了手机也换了还能不能救这种场景我处理过好几回。分两种情况如果你是普通用户那就是没有自救路径必须找 GitLab 管理员管理员用第 4.5 节的 rails console 命令给你解绑 2FA。如果你是 SaaS 版 GitLabGitLab.com没有管理员权限唯一的自救是如果你曾经下载过恢复码就从加密备份里恢复如果恢复码也没了联系官方支持并证明账号归属过程非常漫长所以恢复码一定要留备份。如果是团队内部自建 GitLab我建议管理员在运维文档里留存一张“2FA 紧急解绑流程”的页面上面记录着 rails console 命令。这个页面权限严格控制只能管理员看否则这个“后门”本身就是漏洞。5.2 手机时间不准导致验证码一直报错GitLab 的 TOTP 验证失败最常出现的一种情况是“验证码输入没错但提示 invalid”。用手头手机打开其他任何 TOTP 认证码做对比如果所有验证码都差一分钟左右基本能判定是手机时间漂移。Google Authenticator 的对策是App 内设置→时间校正→ 立即同步。iOS 和 Android 都在设置项里能找。校正完再过 30 秒输入新验证码基本就通了。服务器时间不用自己改GitLab 容器默认走 NTP除非你自己在 Docker 部署时把系统时间调乱了。5.3 浏览器扩展自动填充不灵怎么办如果你选的是 Bitwarden 或者其他浏览器扩展方案常见的“不灵”场景有两种。第一种是扩展没有解锁浏览器重启后主密码没输LiFi 扩展处于锁定状态页面上的 6 位码框自然不会有提示。第二种是网页的登录表单结构特殊GitLab 的 2FA 输入框本身是普通文本输入框常规扩展应该都能识别如果个别站点不行就手动从扩展里复制验证码粘贴进去。更隐蔽的一个坑浏览器扩展根据“当前登录的 GitLab 用户名”来匹配合适的 TOTP 条目如果你在同一个浏览器里同时登录了多个 GitLab 账号扩展可能匹配到默认条目自动填充后报错。解决方式是手动点扩展选择对应的 GitLab 账号条目再填充。5.4 递归困境用 GitLab 账号登录第三方服务时卡在 2FA很多人还会遇到这种情况GitLab 里集成了 Jenkins、SonarQube、Harbor 等第三方系统这些系统通过 OAuth 方式接入 GitLab 单点登录。开启 2FA 后第三方系统跳转回 GitLab 授权时有些老系统的 OAuth 回调并不会给你弹 2FA 验证页而是直接报错。这种情况基本要升级第三方系统的版本或者把 OAuth 应用改成 Private Application PAT 方式接入。如果第三方应用不支持 OAuth 换 token 的 2FA 校验也可以用 Project Access Token 或 Deploy Token 代替个人账号授权。5.5 多人共用一个 GitLab 账号的治理兜底不提倡多人共用账号但很多企业历史遗留就是这么干的。一旦在这个共享账号上开 2FA等于全组人都要拿同一个手机验证码运维活活变成传话游戏。正确的做法是彻底分账号每个人一个账号再通过 Group 的成员权限管理仓库权限。如果是历史遗留必须过渡建议别对这个共享账号开 2FA而是先用 Group Access Token 解决 CI/CD 的临时访问需求然后排期拆账号。最后再分享两个小技巧第一恢复码我习惯打印一份纸质的放在钱包里同时 Bitwarden 里加密存一份电子版。这份备份平时基本用不上但换手机、出差丢设备时它就是救命稻草。第二团队里如果有人 2FA 被锁管理员解绑后记得要求对方用“新验证器 新恢复码”重新绑定顺便把旧恢复码作废——我遇到过解绑后用户忘了重新绑定结果账号裸奔了一周才被发现。GitLab 的双因素认证开启只是起点真正的安全建设是在它之上把恢复码、PAT、SSH key、CI/CD token 四套凭证分开管理各自最小化权限。代码仓库是整个公司的命脉值得多花一点时间把这条链路上的认证做扎实。
阅读完成 · 觉得有帮助?