{{< details >}}

  • Tier: 基础版, 专业版, 旗舰版
  • Offering: JihuLab.com, 私有化部署

{{< /details >}}

极狐GitLab 没有内置支持在构建环境中管理 SSH 密钥(即极狐GitLab Runner 运行的地方)。

当您想要:

  1. 检出内部子模块。
  2. 使用软件包管理器下载私有软件包。例如,Bundler。
  3. 将应用程序部署到您自己的服务器,或者例如 Heroku。
  4. 从构建环境对远程服务器执行 SSH 命令。
  5. 从构建环境使用 Rsync 同步文件到远程服务器。

如果上述任何一项引起您的注意,那么您很可能需要一个 SSH 密钥。

最广泛支持的方法是通过扩展您的 .gitlab-ci.yml 来注入 SSH 密钥到构建环境中,这是一个适用于任何类型执行器(例如 Docker 或 shell)的解决方案。

创建和使用 SSH 密钥

在极狐GitLab CI/CD 中创建和使用 SSH 密钥:

  1. 使用 ssh-keygen 在本地创建一个新的 SSH 密钥对
  2. 将私钥作为文件类型 CI/CD 变量添加到您的项目中。变量值必须以换行符(LF 字符)结尾。要添加换行符,请在 SSH 密钥最后一行的末尾按 EnterReturn,然后在 CI/CD 设置中保存。
  3. 在作业中运行 ssh-agent,加载私钥。
  4. 将公钥复制到您想访问的服务器上(通常在 ~/.ssh/authorized_keys 中)。如果您访问的是私有极狐GitLab 仓库,您还需要将公钥添加为部署密钥

在下面的示例中,ssh-add - 命令不会在作业日志中显示 $SSH_PRIVATE_KEY 的值,尽管如果启用调试日志记录,它可能会被暴露。您可能还想检查流水线的可见性

使用 Docker 执行器时的 SSH 密钥

当您的 CI/CD 作业在 Docker 容器中运行(意味着环境是隔离的)并且您想要在私有服务器上部署代码时,您需要一种方式来访问它。在这种情况下,您可以使用 SSH 密钥对。

  1. 您首先必须创建一个 SSH 密钥对。有关更多信息,请按照说明生成 SSH 密钥不要给 SSH 密钥添加密码,或者 before_script 会提示输入密码。

  2. 创建一个新的文件类型 CI/CD 变量
    • Key 字段中输入 SSH_PRIVATE_KEY
    • Value 字段中粘贴您之前创建的密钥对中的 私钥 内容。确保文件以换行符结尾。要添加换行符,请在 SSH 密钥最后一行的末尾按 EnterReturn 后保存更改。
  3. 使用 before_script 动作修改您的 .gitlab-ci.yml。在下面的示例中,假设使用的是基于 Debian 的镜像。根据需要进行编辑:

    before_script:
      ##
      ## 如果未安装 ssh-agent,则安装它,Docker 需要它。
      ## (如果您使用的是基于 RPM 的镜像,请将 apt-get 更改为 yum)
      ##
      - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    
      ##
      ## 在构建环境中运行 ssh-agent
      ##
      - eval $(ssh-agent -s)
    
      ##
      ## 给予正确的权限,否则 ssh-add 将拒绝添加文件
      ## 将存储在 SSH_PRIVATE_KEY 文件类型 CI/CD 变量中的 SSH 密钥添加到代理存储中
      ##
      - chmod 400 "$SSH_PRIVATE_KEY"
      - ssh-add "$SSH_PRIVATE_KEY"
    
      ##
      ## 创建 SSH 目录并给予正确的权限
      ##
      - mkdir -p ~/.ssh
      - chmod 700 ~/.ssh
    
      ##
      ## 可选地,如果您将使用任何 Git 命令,请设置用户名和电子邮件。
      ##
      # - git config --global user.email "user@example.com"
      # - git config --global user.name "User name"
    

    before_script 可以设置为默认或每个作业。

  4. 确保私有服务器的 SSH 主机密钥已验证

  5. 最后一步,将您在第一步中创建的 公钥 添加到您希望从构建环境内部访问的服务中。如果您访问的是私有极狐GitLab 仓库,您必须将其添加为部署密钥

完成了!您现在可以在构建环境中访问私有服务器或仓库。

使用 Shell 执行器时的 SSH 密钥

如果您使用的是 Shell 执行器而不是 Docker,则更容易设置 SSH 密钥。

您可以从安装极狐GitLab Runner 的机器生成 SSH 密钥,并将该密钥用于在该机器上运行的所有项目。

  1. 首先,登录运行您的作业的服务器。

  2. 然后,从终端以 gitlab-runner 用户身份登录:

    sudo su - gitlab-runner
    
  3. 按照说明生成 SSH 密钥生成 SSH 密钥对。不要给 SSH 密钥添加密码,否则 before_script 会提示输入密码。

  4. 最后一步,将您之前创建的 公钥 添加到您希望从构建环境内部访问的服务中。如果您访问的是私有极狐GitLab 仓库,您必须将其添加为部署密钥

生成密钥后,尝试登录到远程服务器以接受指纹:

ssh example.com

要访问 JihuLab.com 上的仓库,您将使用 git@gitlab.com

验证 SSH 主机密钥

检查私有服务器自己的公钥是一个好习惯,以确保您没有被中间人攻击。如果发生任何可疑情况,您会注意到,因为作业会失败(当公钥不匹配时,SSH 连接会失败)。

要找出服务器的主机密钥,请从可信网络(理想情况下,从私有服务器本身)运行 ssh-keyscan 命令:

## 使用域名
ssh-keyscan example.com

## 或者使用 IP
ssh-keyscan 10.0.2.2

创建一个新的文件类型 CI/CD 变量,将 SSH_KNOWN_HOSTS 作为 “Key”,并将 ssh-keyscan 的输出作为 “Value” 添加。确保文件以换行符结尾。要添加换行符,请在 SSH 密钥最后一行的末尾按 EnterReturn 后保存更改。

如果您必须连接到多个服务器,则所有服务器主机密钥必须收集在变量的 Value 中,每行一个密钥。

{{< alert type=”note” >}}

通过使用文件类型 CI/CD 变量而不是直接在 .gitlab-ci.yml 中使用 ssh-keyscan,其好处在于如果主机域名由于某种原因发生更改,您不必更改 .gitlab-ci.yml。此外,值是您预定义的,这意味着如果主机密钥突然更改,CI/CD 作业不会失败,因此服务器或网络存在问题。

{{< /alert >}}

现在已经创建了 SSH_KNOWN_HOSTS 变量,除了上面的 .gitlab-ci.yml 的内容,您必须添加:

before_script:
  ##
  ## 假设您创建了 SSH_KNOWN_HOSTS 文件类型 CI/CD 变量,取消注释下面的两行。
  ##
  - cp "$SSH_KNOWN_HOSTS" ~/.ssh/known_hosts
  - chmod 644 ~/.ssh/known_hosts

  ##
  ## 或者,使用 ssh-keyscan 扫描您的私有服务器的密钥。
  ## 将 example.com 替换为您的私有服务器的域名。如果您有多个服务器要连接,请重复该命令。包含 -t 标志以指定密钥类型。
  ##
  # - ssh-keyscan -t rsa,ed25519 example.com >> ~/.ssh/known_hosts
  # - chmod 644 ~/.ssh/known_hosts

  ##
  ## 您可以选择禁用主机密钥检查。请注意,通过添加该选项,您容易受到中间人攻击。
  ## WARNING: 仅在 Docker 执行器中使用此选项,如果在 shell 中使用它,您将覆盖用户的 SSH 配置。
  ##
  # - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config'

故障排查

Error loading key "/builds/path/SSH_PRIVATE_KEY": error in libcrypto 消息

如果 SSH 密钥格式错误,则可能返回此消息。

将 SSH 密钥保存为文件类型 CI/CD 变量时,值必须以换行符(LF 字符)结尾。要添加换行符,请在 -----END OPENSSH PRIVATE KEY----- 行的末尾按 EnterReturn 后保存变量。