在数据库中快速查找授权的 SSH 密钥

note本文档描述了 authorized_keys 文件的直接替换。对于普通(非部署密钥)用户,请考虑使用 SSH 证书。它们甚至更快,但不是直接替代品。

随着用户数量的增长,常规 SSH 操作变得缓慢,因为 OpenSSH 通过线性搜索搜索密钥来授权用户。在最坏的情况下,例如当用户无权访问极狐GitLab 时,OpenSSH 会扫描整个文件连搜索密钥。这可能会花费大量时间和磁盘 I/O,从而延迟用户尝试推送或拉取仓库的时间。更糟糕的是,如果用户频繁添加或删除密钥,操作系统可能无法缓存 authorized_keys 文件,从而导致磁盘被重复访问。

极狐GitLab Shell 通过提供一种在数据库中快速索引查找来授权 SSH 用户的方法,来解决这个问题。本页介绍如何启用快速查找授权的 SSH 密钥。

caution需要 OpenSSH 版本 6.9+,因为 AuthorizedKeysCommand 必须能够接受指纹。使用 sshd -V 检查服务器上 OpenSSH 的版本。

Geo 要求使用快速查找

云原生极狐GitLab 不同,Omnibus GitLab 默认管理位于 git 用户主目录中的 authorized_keys 文件。对于大多数安装实例,此文件位于 /var/opt/gitlab/.ssh/authorized_keys 下,但您可以使用以下命令在系统上找到 authorized_keys

getent passwd git | cut -d: -f6 | awk '{print $1"/.ssh/authorized_keys"}'

authorized_keys 文件包含允许访问极狐GitLab 的用户的所有公共 SSH 密钥。但是,为了维护单一事实来源,必须将 Geo 配置为通过数据库查找执行 SSH 指纹查找。

作为设置 Geo 的一部分,您需要针对主要节点和次要节点执行以下概述的步骤,但必须仅在主要节点上取消选中**写入“授权密钥”文件 **,因为如果数据库复制正在工作,它会自动反映在次要节点上。

通过极狐GitLab Shell 设置快速查找

极狐GitLab Shell 提供了一种通过对极狐GitLab 数据库进行快速索引查找来授权 SSH 用户的方法。极狐GitLab Shell 使用 SSH 密钥的指纹来检查用户是否有权访问极狐GitLab。

将以下内容添加到您的 sshd_config 文件中。该文件通常位于 /etc/ssh/sshd_config,但如果您使用的是 Omnibus Docker,它位于 /assets/sshd_config

Match User git    # Apply the AuthorizedKeysCommands to the git user only
  AuthorizedKeysCommand /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k
  AuthorizedKeysCommandUser git
Match all    # End match, settings apply to all users again

重新加载 OpenSSH:

# Debian or Ubuntu installations
sudo service ssh reload

# CentOS installations
sudo service sshd reload

通过在 authorized_keys 文件中注释掉您的用户密钥来确认 SSH 正在工作(以 # 开始注释它的行),然后从您的本地计算机尝试提取仓库或运行:

ssh -T git@gitlab.example.com

成功的拉取或欢迎消息意味着极狐GitLab 能够在数据库中找到密钥,因为它不存在于文件中。

note对于源安装实例,该命令将位于 /home/git/gitlab-shell/bin/gitlab-shell-authorized-keys-check。您可能需要考虑在其他地方创建一个包装脚本,因为此命令必须由 root 拥有,并且不能由组或其他人写入。您还可以考虑根据需要更改此命令的所有权,但可能需要在 gitlab-shell 升级期间临时更改所有权。
caution在确认 SSH 工作正常之前不要禁用写入;否则,文件很快就会过时。

在查找失败(很常见)的情况下,仍会扫描 authorized_keys 文件。因此,只要存在大文件,Git SSH 的性能对于许多用户来说仍然会很慢。

要禁用对 authorized_keys 文件的写入:

  1. 在顶部栏上,选择 主菜单 > 管理员
  2. 在左侧边栏中,选择 设置 > 网络
  3. 展开 性能优化
  4. 清除 使用 authorized_keys 文件来验证 SSH 密钥 复选框。
  5. 选择 保存更改

再次,通过在 UI 中删除用户的 SSH 密钥、添加新密钥并尝试提取仓库来确认 SSH 是否正常工作。

然后您可以备份和删除您的 authorized_keys 文件以获得最佳性能。 当前用户的密钥已经存在于数据库中,因此无需迁移,无需用户重新添加其密钥。

如何返回使用 authorized_keys 文件

这个概述很简短。有关更多上下文,请参阅上述说明。

  1. 重建 authorized_keys 文件
  2. 允许写入 authorized_keys 文件。
    1. 在顶部栏上,选择 主菜单 > 管理员
    2. 在左侧边栏中,选择 设置 > 网络
    3. 展开 性能优化
    4. 选中 使用 authorized_keys 文件来验证 SSH 密钥 复选框。
  3. 如果您使用的是 Omnibus Docker,请从 /etc/ssh/sshd_config/assets/sshd_config 中删除 AuthorizedKeysCommand 行。
  4. 重新加载 sshdsudo service sshd reload

使用 gitlab-sshd 而不是 OpenSSH

引入于 14.5 版本作为 Alpha 发布功能,适用于私有化部署版用户。

cautiongitlab-sshd 处于 Alpha 状态。还没有准备好用于生产。

gitlab-sshd 是用 Go 编写的一个独立的 SSH 服务器。它作为 gitlab-shell 包的一部分提供。作为 OpenSSH 的替代方案,它的内存使用量较低,并且支持 IP 地址的群组访问限制,用于在代理后面运行的应用程序。

gitlab-sshd 是 OpenSSH 的轻量级替代方案,用于提供 SSH 操作。 虽然 OpenSSH 使用受限的 shell 方法,但 gitlab-sshd 更像是一个现代多线程服务器应用程序,响应传入的请求。主要区别在于 OpenSSH 使用 SSH 作为传输协议,而 gitlab-sshd 使用远程过程调用 (RPC)。

极狐GitLab Shell 的功能不仅限于 Git 操作。

如果您正在考虑从 OpenSSH 切换到 gitlab-sshd,请考虑以下问题:

  • gitlab-sshd 组件仅适用于云原生 Helm Charts 部署。
  • gitlab-sshd 支持 PROXY 协议。它可以在依赖它的代理服务器后面运行,例如 HAProxy。PROXY 协议默认不启用,但可以通过 Helm chart 设置启用。
  • 默认情况下,gitlab-sshd 绑定到端口 22,但您可以在 Helm chart 中配置不同的端口。
  • gitlab-sshd 支持 SSH 证书。

从 OpenSSH 切换到 gitlab-sshd

  1. gitlab-shell chart sshDaemon 选项设置为 gitlab-sshd。例如:

    gitlab:
      gitlab-shell:
        sshDaemon: gitlab-sshd
    
  2. 执行 Helm 升级。

SELinux 支持和限制

极狐GitLab 支持使用 SELinux 进行 authorized_keys 数据库查找。

由于 SELinux 策略是静态的,系统目前不支持更改内部网络服务器端口的功能。管理员必须为环境创建一个特殊的 .te 文件,因为它不是动态生成的。

更多文档

gitlab-sshd 的其他技术文档可以在极狐GitLab Shell 文档页面上找到。

故障排查

如果您的 SSH 传输速度或导致高 CPU 负载,请务必检查 /var/log/btmp 的大小,并确保它定期轮换或在达到一定大小后轮换。 如果这个文件非常大,极狐GitLab SSH 快速查找会导致更频繁地遇到瓶颈,从而进一步降低性能。 如果可以的话,您可以考虑在 sshd_config 中禁用 UsePAM 以避免完全读取 /var/log/btmp

在正在运行的 sshd: git 进程上运行 stracelsof 会返回调试信息。 要通过 IP x.x.x.x 的 SSH 连接在正在进行的 Git 上获取 strace,请运行:

sudo strace -s 10000 -p $(sudo netstat -tp | grep x.x.x.x | egrep 'ssh.*: git' | sed -e 's/.*ESTABLISHED *//' -e 's#/.*##')

或者为通过 SSH 进程运行的 Git 获取一个 lsof

sudo lsof -p $(sudo netstat -tp | egrep 'ssh.*: git' | head -1 | sed -e 's/.*ESTABLISHED *//' -e 's#/.*##')