【问题标题】:Getting GitLab CI to clone private repositories让 GitLab CI 克隆私有存储库
【发布时间】:2014-10-30 14:31:26
【问题描述】:

我设置了 GitLab 和 GitLab CI 来托管和测试我的一些私人存储库。对于这个系统下的作曲家模块,我设置了 Satis 来解析我的私有包。

显然,这些私有包需要一个 ssh 密钥来克隆它们,而我在终端中有这个工作 - 我可以运行 composer install 并获取这些包,只要我在 shell 中添加了带有 ssh-add 的密钥。

但是,当在 GitLab CI 中运行我的测试时,如果项目具有任何这些依赖项,则测试将无法完成,因为我的 GitLab 实例需要身份验证才能获取 deps(显然),并且测试失败并显示 Host key verification failed

我的问题是如何设置它以便当运行者运行测试时它可以在没有密码的情况下向 gitlab 进行身份验证?我已经尝试在我的跑步者~/.ssh 文件夹中放置一个无密码的 ssh 密钥,但是构建甚至不会添加密钥“eval ssh-agent -s”,然后是 ssh-add 似乎无法说明代理没有运行。 ..

【问题讨论】:

  • 截至 2017 年,排名最高的答案已过时。 Marco's answer using GIT_SUBMODULE_STRATEGY 是正确的。我专门添加了这个功能,以避免处理注入 SSH 密钥的混乱。
  • @JonathonReinhart 但是这个解决方案不是安全问题吗?只要我知道相对 URL,我就可以克隆任何私有 GitLab 存储库?跑步者可以压缩克隆的内容并通过电子邮件发送。
  • @Paebbels 不,这不是问题。从 GitLab 8.12 开始,CI 作业运行 as the user that triggered the pipeline,其令牌具有一组减少的权限。 CI 作业只能访问与推送代码的人相同的存储库。

标签: ssh continuous-integration gitlab gitlab-ci gitlab-ci-runner


【解决方案1】:
  1. 如果您的 CI 运行器在容器模型上运行,您需要使用部署密钥。文档:https://docs.gitlab.com/ee/user/project/deploy_tokens/#git-clone-a-repository
git clone https://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
  1. 创建您的部署令牌
  2. 在 CI 管道变量中添加您的令牌
  3. 确保您的容器有 git 并通过 insteadOf 更改 git URL
  image: docker:latest
  before_script:
    - apk add --no-cache curl jq python3 py3-pip git
    - git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.example.come/".insteadOf 'git@gitlab.example.come:'

替换网址:https://docs.gitlab.com/ee/user/project/working_with_projects.html#authenticate-git-fetches

【讨论】:

    【解决方案2】:

    如果您使用的是基于 alpine 的图像(可能是 docker:latestdocker:dind),您的 before_script 可能如下所示:

    before_script:
        - apk add --no-cache openssh-client git
        - mkdir -p /.ssh && touch /.ssh/known_hosts
        - ssh-keyscan gitlab.com >> /.ssh/known_hosts
        - echo $SSH_KEY | base64 -d >> /.ssh/id_rsa && chmod 600 /.ssh/id_rsa
        - git clone git@git.myhost.com:mygroup/myproject.git
    

    【讨论】:

      【解决方案3】:

      我将其发布为答案,因为其他人并不完全清楚和/或详细的恕我直言

      从 GitLab 8.12+ 开始,假设子模块 repo 与请求它的服务器位于同一服务器中,您现在可以:

      1. 像往常一样使用 git 子模块设置 repo (git submodule add git@somewhere:folder/mysubmodule.git)

      2. 如下修改你的.gitmodules文件

         [submodule "mysubmodule"]
           path = mysubmodule
           url = ../../group/mysubmodule.git
        

        其中../../group/mysubmodule.git 是从您的存储库到子模块的相对路径。

      3. 将以下行添加到gitlab-ci.yml

         variables:
           GIT_SUBMODULE_STRATEGY: recursive
        

        指示运行器在构建之前获取所有子模块。

      警告:如果您的跑步者似乎忽略了GIT_SUBMODULE_STRATEGY 指令,您可能应该考虑updating it

      (来源:https://docs.gitlab.com/ce/ci/git_submodules.html

      【讨论】:

      • 我不赞成这种方法,因为我认为 Gitlab 不应该强迫我以特定方式配置子模块。我更喜欢use Gitlab tokens and keep the configuration in .gitlab-ci.yml
      • 如果您想在本地运行git submodule update --init --recursive,此解决方案是否有效?
      • 特别是,如何使用这个.gitmodules.gitlab-ci.yml文件在本地运行gitlab-runner
      • 它不适用于另一台服务器上的存储库,它不能有相对路径。
      • @Gus 是的,如果您在本地运行 git submodule update --recursive --remote 它可以工作。就我而言,我所有的子模块都在同一组下的 gitlab 中。
      【解决方案4】:

      将它添加到 .gitlab-ci.yml 对我来说是诀窍。 (这里提到:https://docs.gitlab.com/ee/user/project/new_ci_build_permissions_model.html#dependent-repositories

      before_script:
          echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc
      

      (我尝试按照上述答案之一设置 SSH_PRIVATE_KEY,但它不起作用)

      【讨论】:

        【解决方案5】:

        在不更改 git 存储库结构的情况下解决此问题的一种方法是执行以下步骤:

        1。获取 ssh 主机密钥

        获取您正在运行的服务器的 ssh 主机密钥。对于gitlab.com

        1. 运行ssh-keyscan gitlab.com &gt; known_hosts
        2. 检查ssh-keygen -lf known_hosts 是否与here 报告的指纹一致。
        3. 复制known_hosts 的内容并将其粘贴到存储库中名为SSH_KNOWN_HOSTS 的变量中。

        这一步只需要一次。

        2。将作业配置为使用 ssh

        before_script:
            - git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "git@gitlab.com:"
            - mkdir -p ~/.ssh
            - chmod 700 ~/.ssh
            - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
            - chmod 644 ~/.ssh/known_hosts
        

        如果您尝试执行git clone git@gitlab.com:pip install -e git+ssh://git@gitlab.com/..."ssh://git@gitlab.com" 位可能会有所不同;根据您的需要进行调整。

        此时,您的 CI 可以使用 ssh 从另一个(私有)存储库中获取。

        3。 [奖金干]

        一般用this trick写:

        .enable_ssh: &enable_ssh |-
            git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "ssh://git@gitlab.com"
            mkdir -p ~/.ssh
            chmod 700 ~/.ssh
            echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
            chmod 644 ~/.ssh/known_hosts
        

        并在需要它的工作上启用它

        test:
            stage: test
            before_script:
                - *enable_ssh
            script:
                - ...
        

        【讨论】:

        • 当我需要使用 gitlab 和 go get 特别是 git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "https://gitlab.com" 获取私有存储库时,[3] 为我工作(它有点修改)
        【解决方案6】:

        另见其他解决方案:


        这里有一个完整的 SSH 密钥方法:

        一般设计

        • 生成一对 SSH 密钥
        • 将私有变量添加为项目的安全环境变量
        • 在 GitLab-CI 上为您的测试脚本提供私有脚本
        • 在每个私有依赖项上添加公共密钥作为部署密钥

        生成一对公钥和私钥 SSH 密钥

        生成一对不带密码的公钥和私钥:

        ssh-keygen -b 4096 -C "<name of your project>" -N "" -f /tmp/name_of_your_project.key
        

        将私有 SSH 密钥添加到您的项目中

        您需要将密钥作为安全环境变量添加到您的项目中 以下:

        • 浏览https://&lt;gitlab_host&gt;/&lt;group&gt;/&lt;project_name&gt;/variables
        • 点击“添加变量”
        • SSH_PRIVATE_KEY 填充文本字段Key
        • 使用 SSH 私钥本身填写文本字段 Value
        • 点击“保存更改”

        向您的测试脚本公开 SSH 私钥

        为了使您的私钥可用于您的测试脚本,您需要添加 将以下内容添加到您的 .gitlab-ci.yml 文件中:

        before_script:
          # install ssh-agent
          - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
          # run ssh-agent
          - eval $(ssh-agent -s)
          # add ssh key stored in SSH_PRIVATE_KEY variable to the agent store
          - ssh-add <(echo "$SSH_PRIVATE_KEY")
          # disable host key checking (NOTE: makes you susceptible to man-in-the-middle attacks)
          # WARNING: use only in docker container, if you use it with shell you will overwrite your user's ssh config
          - mkdir -p ~/.ssh
          - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
        

        Code Snippet comes from GitLab documentation

        将公共 SSH 密钥作为部署密钥添加到所有私有依赖项

        您需要将公共 SSH 密钥注册为部署密钥到您的所有私有 依赖如下:

        • 浏览https://&lt;gitlab_host&gt;/&lt;group&gt;/&lt;dependency_name&gt;/deploy_keys
        • 点击“新部署密钥”
        • 用您的项目名称填写文本字段Title
        • 使用 SSH 公钥本身填充文本字段 Key
        • 点击“创建部署密钥”

        【讨论】:

        • @Ridermansb 感谢您的链接。答案来自个人文档。我忘记了代码 sn-p 的来源。值得一提的是。再次感谢您的指出。
        • 不要回显来禁用 StrictHostKeyChecking(并冒着意外破坏真实系统的 ssh 配置的风险),而是添加一个具有已知主机的 gitlab CI 变量,如 KNOWN_HOSTS。详情请见:docs.gitlab.com/ee/ci/ssh_keys/#verifying-the-ssh-host-keys
        • 我可以使用SSH_PRIVATE_KEY以外的名字吗?
        • Becko,您可以更改 var SSH_PRIVATE_KEY 的名称。如果你这样做了,请务必在任何地方进行更新。
        • 安全警告:该文档未在私钥上使用密码。
        【解决方案7】:

        currently accepted answer 将特定于 Gitlab 的要求嵌入到我的 .gitmodules 文件中。这会强制本地开发使用特定的目录布局,并且会使迁移到另一个版本控制平台变得复杂。

        相反,我遵循了Juddling's answer 中的建议。这是一个更完整的答案。

        我的.gitmodules 文件有以下内容:

        [submodule "myproject"]
            url = git@git.myhost.com:mygroup/myproject.git
        

        在我的gitlab-ci.yml 我有以下内容:

        build:
          stage: build
          before_script:
            - git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@git.myhost.com/".insteadOf "git@git.myhost.com:"
            - git submodule sync && git submodule update --init
        

        尾随的/:git config 行中很关键,因为我们正在从SSH 身份验证映射到HTTPS。这让我因“非法端口号”错误而绊倒了一段时间。

        我喜欢这个解决方案,因为它将特定于 Gitlab 的要求嵌入到特定于 Gitlab 的文件中,而其他所有文件都会忽略该文件。

        【讨论】:

        • 为了避免其他人犯同样愚蠢的模式匹配错误,对于托管在 gitlab.com 上的项目,git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/".insteadOf "git@gitlab.com:"
        • @Gus,你能发布一个 ci 配置文件的工作示例吗?我在这里发布了一个类似的问题:stackoverflow.com/questions/58040183/… 但根本无法完成这项工作
        【解决方案8】:

        我使用deploy tokens 解决了这个问题,因为为测试运行程序设置 SSH 密钥似乎有点冗长。

        git clone http://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
        

        部署令牌是每个项目的,并且是只读的。

        【讨论】:

          【解决方案9】:

          如果您不想摆弄 ssh 密钥或子模块,您可以覆盖 git 配置中的 repo 以使用作业令牌进行身份验证(在 gitlab-ci.yml 中):

          before_script:
            - git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.example.com/group/repo.git".insteadOf git@gitlab.example.com:group/repo.git
          

          【讨论】:

          • 我遇到了一个问题 - git config global 在我的跑步者的下一个作业中持续存在。它完全破坏了CI。你有过这个问题吗?我无法从我的 gitlab 克隆任何资源,因为 CI_JOB_TOKEN 已过时。
          • @Darkowic 我使用的是 Docker 运行器,所以我没有遇到这个问题。
          • 我也是。虽然我今天解决了 :) 它是因为 npm ... 默认情况下 npm install 修改 package-lock.json。当您在 CI 中设置为仅获取更改而不是克隆时,此修改后的 packge-lock.json 文件会在作业之间持续存在,并且 npm 无法安装任何东西...
          • 这个解决方案是最优雅的。它适用于 dockerized GitLab 社区版 11.6.4
          • 您也可以省略 group 和 repo 以将作业令牌用于 gitlab 实例上的所有 repos。见gist.github.com/Kovrinic/ea5e7123ab5c97d451804ea222ecd78a
          【解决方案10】:

          好像终于有reasonable solution了。

          简而言之,从 GitLab 8.12 开始,您只需在 .submodules 中使用相对路径,git submodule update --init 就可以正常工作

          【讨论】:

          • 这是上述 Marco A 答案的不完整版本。
          【解决方案11】:

          我有一个场景,我必须在 3 个不同的脚本中使用我的 ssh 密钥,所以我将 ssh 密钥内容放在一个 shell 脚本中,并在其他 3 个脚本之前先调用它。这最终不起作用,我认为是由于 ssh-agent 没有在 shell 脚本之间持续存在,或者类似的东西。我最终实际上只是将私钥输出到~/.ssh/id_rsa 文件中,这肯定会持续到其他脚本。

          .gitlab-ci.yml

          script:
              - ci/init_ssh.sh
              - git push # or whatever you need ssh for
          

          ci/init_ssh.sh

          # only run in docker:
          [[ ! -e /.dockerenv ]] && exit 0
          
          mkdir -p ~/.ssh
          echo "$GITLAB_RUNNER_SSH_KEY" > ~/.ssh/id_rsa
          chmod 400 ~/.ssh/id_rsa
          echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > /.ssh/config
          

          它就像一个魅力!

          【讨论】:

          • 嗨@user3246077!非常感谢您的回答。我发现了一个错误,在最后一行中缺少引用用户家的~ 符号。你能解决它吗?
          猜你喜欢
          • 2022-01-23
          • 1970-01-01
          • 2015-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-02
          • 1970-01-01
          相关资源
          最近更新 更多