部署令牌

您可以使用部署令牌来启用部署任务的认证,这独立于用户账号。在大多数情况下,您可以从外部宿主机使用部署令牌,比如构建服务器或 CI/CD 服务器。

取决于你的需要,你可能想要使用部署令牌来访问仓库。

属性 部署 key 部署令牌
共享 在多个项目之间共享,即使位于不同的群组。 属于群组或项目。
在外部宿主机上生成公共 SSH key。 在极狐GitLab 实例上生成并在特定时间提供给用户。
可访问的资源 Git 仓库的 SSH 访问 HTTP 访问 Git 仓库、软件包仓库和容器仓库。

如果启用了外部认证,则 Git 无法使用部署 key。

范围

当部署 key 创建的时候会有定义好的范围:

  • 项目部署 key: 访问仅限于选择的项目。
  • 公共的部署 key: 可以为实例中的 任何 项目赋予访问。要访问每个项目的话,必须要为用户赋予维护者角色。

创建完毕后,你就无法再修改部署 key 的范围了。

权限

当部署 key 创建的时候就会给与一定的权限:

  • 仅读: 仅可以从仓库读取仅读的部署 key。
  • 仅写: 可以从项目读写具有读写权限的部署 key。

你可以在创建后修改部署 key 的权限。修改项目部署 key 的权限仅适用于当前项目。

如果推送使用了部署 key 来触发额外的流程,则必须要授权 key 的创建者授权,比如:

  • 当使用部署 key 推送代码到受保护分支时,则部署 key 的创建者必须具有访问该分支的权限。
  • 当部署 key 被用于推送提交以触发 CI/CD 流水线时,部署 key 的创建者必须要能够访问 CI/CD 资源,包括受保护环境和密钥变量。

安全指示

部署密钥旨在促进与GitLab的非人类交互。例如,您可以使用部署密钥 来授予在您组织的服务器上自动运行的脚本权限。

您应该创建一个专门的账户来充当服务账户,并使用服务账户创建部署密钥。 如果您使用另一个用户账户来创建部署密钥,那么该用户将被授予直到部署密钥被撤销为止的特权。

此外:

  • 部署密钥即使创建它们的用户从群组或项目中被移除也能工作。
  • 部署密钥的创建者保留对群组或项目的访问权限,即使用户被降级或移除。
  • 当部署密钥在受保护分支规则中被指定时,部署密钥的创建者:
    • 获得对受保护分支的访问权限,以及对部署密钥本身的访问权限。
    • 如果部署密钥有读写权限,可以推送到受保护分支。 这即使分支对所有用户的更改进行了保护也是如此。

与所有敏感信息一样,您应该确保只有需要访问秘密的人才能读取它。 对于人类交互,使用与用户相关的凭证,例如个人访问令牌。

为了帮助检测潜在的秘密泄露,您可以使用审计事件功能。

查看部署密钥

要查看项目可用的部署密钥:

  1. 在左侧导航栏,选择 搜索或前往 并找到你的项目。
  2. 选择 设置 > 仓库
  3. 展开 部署密钥

会列出可用的部署 key:

  • 启用的部署密钥: 能够访问项目的部署 key。
  • 可私有访问的部署密钥: 项目部署令牌无法访问项目。
  • 可公开访问的部署密钥: 不能够访问项目的公共部署 key。

创建项目部署密钥

先决条件:

  • 要创建群组部署令牌,您必须具有群组的拥有者角色。
  • 生成 SSH 密钥对。你必须将公钥放在需要访问仓库的主机上。
  1. 在左侧边栏中,选择 搜索或转到 并找到您的项目。
  2. 选择 设置 > 仓库
  3. 展开 部署令牌
  4. 选择 添加令牌
  5. 完成字段。
  6. 可选。要赋予 read-write 权限,勾选 为此密钥授予写权限
  7. 可选,更新 过期时间

当部署 key 创建时就会被启用。你仅能修改项目部署 key 的名称和权限。如果部署 key 在多个项目中被启用,则你无法修改它的名称。

创建一个公共部署密钥

先决条件:

  • 你必须具有管理员权限。
  • 生成 SSH 密钥对
  • 你必须将公钥放在需要访问仓库的主机上。

要创建一个公共部署密钥:

  1. 在左侧边栏中,在底部,选择 管理员
  2. 选择 部署密钥
  3. 选择 新的部署密钥
  4. 完成字段。
    • 名称 使用有意义的描述。例如,包括外部主机的名称或应用程序的名称。

你仅能修改公共部署密钥的名称。

为公共部署密钥授予项目访问权限

先决条件:

  • 你必须至少具有项目的维护者角色。

要为公共部署密钥授予项目访问权限:

  1. 在左侧边栏中,选择 搜索或转到 并找到您的项目。
  2. 选择 设置 > 仓库
  3. 展开 部署密钥
  4. 选择 公共部署密钥
  5. 在密钥的行中,选择 启用
  6. 为公共部署密钥授予读写权限:
    1. 在密钥的行中,选择 编辑 ( )。
    2. 选择 为此密钥授予写权限 的复选框。

编辑部署密钥的项目访问权限

先决条件:

  • 你必须至少具有项目的维护者角色。

要编辑项目部署密钥的访问权限:

  1. 在左侧边栏中,选择 搜索或转到 并找到您的项目。
  2. 选择 设置 > 仓库
  3. 展开 部署密钥
  4. 在密钥的行中,选择 编辑 ( )。
  5. 选择或清除 为此密钥授予写权限 的复选框。

撤销部署密钥的项目访问

要撤销部署密钥的项目访问权限,请禁用它。任何依赖于部署密钥的服务在密钥禁用时停止工作。

先决条件:

  • 你必须至少具有项目的维护者角色。

要禁用部署密钥:

  1. 在左侧边栏中,选择 搜索或转到 并找到您的项目。
  2. 选择 设置 > 仓库
  3. 展开 部署密钥
  4. 在密钥的行中,选择 禁用 ( )。

禁用部署密钥后会发生什么取决于如下内容:

  • 如果密钥是公开可用的,它从项目中删除但仍可用于 公开可用的部署密钥 标签。
  • 如果密钥是私有可用的,且仅在此项目中使用,它将被删除。
  • 如果密钥是私有可用的,并且也在其他项目中使用,它从项目中删除,但仍可用于 私有可用的部署密钥 标签。

故障排查

部署密钥无法推送到受保护分支

有一些情况下,部署密钥无法推送到受保护分支

当所有的部署密钥都关联到一个账户时,就会出现此问题。因为账户的权限可以改变,这可能会导致出现部署密钥正在工作,但是突然无法推送到受保护分支的情况。

要解决此问题,你可以使用部署密钥 API 为项目服务账户用户创建部署密钥,而不是为你自己的用户创建部署密钥:

  1. 创建服务账户用户
  2. 为服务账户用户创建个人访问令牌。该令牌必须具有 api 权限。
  3. 邀请服务账户用户加入项目
  4. 使用部署密钥 API 为服务账户用户创建部署密钥:

    curl --request POST --header "PRIVATE-TOKEN: <service_account_access_token>" --header "Content-Type: application/json" \
    --data '{"title": "My deploy key", "key": "ssh-rsa AAAA...", "can_push": "true"}' \
    "https://gitlab.example.com/api/v4/projects/5/deploy_keys/"
    

识别与非成员和封禁用户关联的部署密钥

如果你需要找到属于非成员或封禁用户的部署密钥,你可以使用Rails 控制台来使用类似的脚本来识别无法使用的部署密钥:

ghost_user_id = Users::Internal.ghost.id

DeployKeysProject.with_write_access.find_each do |deploy_key_mapping|
  project = deploy_key_mapping.project
  deploy_key = deploy_key_mapping.deploy_key
  user = deploy_key.user

  access_checker = Gitlab::DeployKeyAccess.new(deploy_key, container: project)

  # can_push_for_ref? tests if deploy_key can push to default branch, which is likely to be protected
  can_push = access_checker.can_do_action?(:push_code)
  can_push_to_default = access_checker.can_push_for_ref?(project.repository.root_ref)

  next if access_checker.allowed? && can_push && can_push_to_default

  if user.nil? || user.id == ghost_user_id
    username = 'none'
    state = '-'
  else
    username = user.username
    user_state = user.state
  end

  puts "Deploy key: #{deploy_key.id}, Project: #{project.full_path}, Can push?: " + (can_push ? 'YES' : 'NO') +
       ", Can push to default branch #{project.repository.root_ref}?: " + (can_push_to_default ? 'YES' : 'NO') +
       ", User: #{username}, User state: #{user_state}"
end