部署令牌
您可以使用部署令牌来启用部署任务的认证,这独立于用户账号。在大多数情况下,您可以从外部宿主机使用部署令牌,比如构建服务器或 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的非人类交互。例如,您可以使用部署密钥 来授予在您组织的服务器上自动运行的脚本权限。
您应该创建一个专门的账户来充当服务账户,并使用服务账户创建部署密钥。 如果您使用另一个用户账户来创建部署密钥,那么该用户将被授予直到部署密钥被撤销为止的特权。
此外:
- 部署密钥即使创建它们的用户从群组或项目中被移除也能工作。
- 部署密钥的创建者保留对群组或项目的访问权限,即使用户被降级或移除。
- 当部署密钥在受保护分支规则中被指定时,部署密钥的创建者:
- 获得对受保护分支的访问权限,以及对部署密钥本身的访问权限。
- 如果部署密钥有读写权限,可以推送到受保护分支。 这即使分支对所有用户的更改进行了保护也是如此。
与所有敏感信息一样,您应该确保只有需要访问秘密的人才能读取它。 对于人类交互,使用与用户相关的凭证,例如个人访问令牌。
为了帮助检测潜在的秘密泄露,您可以使用审计事件功能。
查看部署密钥
要查看项目可用的部署密钥:
- 在左侧导航栏,选择 搜索或前往 并找到你的项目。
- 选择 设置 > 仓库。
- 展开 部署密钥。
会列出可用的部署 key:
- 启用的部署密钥: 能够访问项目的部署 key。
- 可私有访问的部署密钥: 项目部署令牌无法访问项目。
- 可公开访问的部署密钥: 不能够访问项目的公共部署 key。
创建项目部署密钥
先决条件:
- 要创建群组部署令牌,您必须具有群组的拥有者角色。
- 生成 SSH 密钥对。你必须将公钥放在需要访问仓库的主机上。
- 在左侧边栏中,选择 搜索或转到 并找到您的项目。
- 选择 设置 > 仓库。
- 展开 部署令牌。
- 选择 添加令牌。
- 完成字段。
- 可选。要赋予
read-write
权限,勾选 为此密钥授予写权限。 - 可选,更新 过期时间。
当部署 key 创建时就会被启用。你仅能修改项目部署 key 的名称和权限。如果部署 key 在多个项目中被启用,则你无法修改它的名称。
创建一个公共部署密钥
先决条件:
- 你必须具有管理员权限。
- 生成 SSH 密钥对。
- 你必须将公钥放在需要访问仓库的主机上。
要创建一个公共部署密钥:
- 在左侧边栏中,在底部,选择 管理员。
- 选择 部署密钥。
- 选择 新的部署密钥。
- 完成字段。
- 为 名称 使用有意义的描述。例如,包括外部主机的名称或应用程序的名称。
你仅能修改公共部署密钥的名称。
为公共部署密钥授予项目访问权限
先决条件:
- 你必须至少具有项目的维护者角色。
要为公共部署密钥授予项目访问权限:
- 在左侧边栏中,选择 搜索或转到 并找到您的项目。
- 选择 设置 > 仓库。
- 展开 部署密钥。
- 选择 公共部署密钥。
- 在密钥的行中,选择 启用。
- 为公共部署密钥授予读写权限:
- 在密钥的行中,选择 编辑 ()。
- 选择 为此密钥授予写权限 的复选框。
编辑部署密钥的项目访问权限
先决条件:
- 你必须至少具有项目的维护者角色。
要编辑项目部署密钥的访问权限:
- 在左侧边栏中,选择 搜索或转到 并找到您的项目。
- 选择 设置 > 仓库。
- 展开 部署密钥。
- 在密钥的行中,选择 编辑 ()。
- 选择或清除 为此密钥授予写权限 的复选框。
撤销部署密钥的项目访问
要撤销部署密钥的项目访问权限,请禁用它。任何依赖于部署密钥的服务在密钥禁用时停止工作。
先决条件:
- 你必须至少具有项目的维护者角色。
要禁用部署密钥:
- 在左侧边栏中,选择 搜索或转到 并找到您的项目。
- 选择 设置 > 仓库。
- 展开 部署密钥。
- 在密钥的行中,选择 禁用 ()。
禁用部署密钥后会发生什么取决于如下内容:
- 如果密钥是公开可用的,它从项目中删除但仍可用于 公开可用的部署密钥 标签。
- 如果密钥是私有可用的,且仅在此项目中使用,它将被删除。
- 如果密钥是私有可用的,并且也在其他项目中使用,它从项目中删除,但仍可用于 私有可用的部署密钥 标签。
故障排查
部署密钥无法推送到受保护分支
有一些情况下,部署密钥无法推送到受保护分支。
- 与部署密钥相关联的所有者与保护分支的项目没有成员关系。
- 与部署密钥相关联的所有者具有的项目成员关系权限低于所需的查看项目代码权限。
- 部署密钥没有项目的读写权限。
- 部署密钥已被撤销。
- 在保护分支的允许推送和合并 部分中选择了 没有人。
当所有的部署密钥都关联到一个账户时,就会出现此问题。因为账户的权限可以改变,这可能会导致出现部署密钥正在工作,但是突然无法推送到受保护分支的情况。
要解决此问题,你可以使用部署密钥 API 为项目服务账户用户创建部署密钥,而不是为你自己的用户创建部署密钥:
- 创建服务账户用户。
- 为服务账户用户创建个人访问令牌。该令牌必须具有
api
权限。 - 邀请服务账户用户加入项目。
-
使用部署密钥 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