GitLab 令牌故障排除
在使用 GitLab 令牌时,您可能会遇到以下问题。
过期的访问令牌
如果现有的访问令牌正在使用中并达到 expires_at 值,该令牌将过期,并且:
- 无法再用于身份验证。
- 在 UI 中不可见。
使用此令牌发出的请求会返回 401 Unauthorized 响应。短时间内从同一 IP 地址发出过多未经授权的请求会导致 GitLab.com 返回 403 Forbidden 响应。
有关身份验证请求限制的更多信息,请参阅 Git 和容器注册表身份验证失败封禁。
从日志中识别过期的访问令牌
先决条件:
您必须:
- 是管理员。
- 能够访问
api_json.log文件。
要识别哪些 401 Unauthorized 请求是由于访问令牌过期而失败,请在 api_json.log 文件中使用以下字段:
| 字段名 | 描述 |
|---|---|
meta.auth_fail_reason |
请求被拒绝的原因。可能的值:token_expired、token_revoked、insufficient_scope 和 impersonation_disabled。 |
meta.auth_fail_token_id |
描述尝试使用的令牌类型和 ID 的字符串。 |
当用户尝试使用过期令牌时,meta.auth_fail_reason 为 token_expired。以下显示了日志条目的摘录:
{
"status": 401,
"method": "GET",
"path": "/api/v4/user",
...
"meta.auth_fail_reason": "token_expired",
"meta.auth_fail_token_id": "PersonalAccessToken/12",
}meta.auth_fail_token_id 表示使用了 ID 为 12 的访问令牌。
要查找有关此令牌的更多信息,请使用个人访问令牌 API。 您还可以使用 API 来轮换令牌。
替换过期的访问令牌
要替换令牌:
- 检查此令牌之前可能被使用过的地方,并从任何可能仍在使用该令牌的自动化中移除它。
- 对于个人访问令牌,使用API
列出最近过期的令牌。例如,访问
https://gitlab.com/api/v4/personal_access_tokens, 并查找具有特定expires_at日期的令牌。 - 对于项目访问令牌,使用 项目访问令牌 API 列出最近过期的令牌。
- 对于群组访问令牌,使用 群组访问令牌 API 列出最近过期的令牌。
- 对于个人访问令牌,使用API
列出最近过期的令牌。例如,访问
- 创建新的访问令牌:
- 对于个人访问令牌,使用 UI 或用户令牌 API。
- 对于项目访问令牌,使用 UI 或项目访问令牌 API。
- 对于群组访问令牌,使用 UI 或群组访问令牌 API。
- 用新的访问令牌替换旧的访问令牌。此过程根据您使用令牌的方式而有所不同,
例如,如果配置为密钥或嵌入到应用程序中。从此令牌发出的请求不应再返回
401响应。
延长令牌有效期
使用此脚本延迟某些令牌的过期时间。
从 GitLab 16.0 开始,所有访问令牌都有过期日期。在部署至少 GitLab 16.0 后, 任何永不过期的令牌将在部署日期一年后过期。
如果这个日期即将到来,并且还有尚未轮换的令牌,您可以使用此脚本来延迟过期时间, 并为用户提供更多时间来轮换他们的令牌。
为特定令牌延长有效期
此脚本延长所有在指定日期过期的令牌的有效期,包括:
- 个人访问令牌
- 群组访问令牌
- 项目访问令牌
对于群组和项目访问令牌,此脚本仅在它们在升级到 GitLab 16.0 或更高版本时被自动设置了过期日期的情况下才延长这些令牌的有效期。如果群组或项目访问令牌是在生成时设置了过期日期,或者已被轮换,则该令牌的有效性取决于对资源的有效成员身份,因此无法使用此脚本延长令牌有效期。
要使用该脚本:
- 在您的终端窗口中,使用
sudo gitlab-rails console启动 Rails 控制台会话。 - 从下一节粘贴整个
extend_expiring_tokens.rb脚本。 如果需要,可以将expiring_date更改为不同的日期。 - 按 Enter。
-
在您的终端窗口中,连接到您的实例。
-
从下一节复制整个
extend_expiring_tokens.rb脚本,并将其保存为实例上的文件:- 将其命名为
extend_expiring_tokens.rb。 - 如果需要,可以将
expiring_date更改为不同的日期。 - 文件必须对
git:git可访问。
- 将其命名为
-
运行以下命令,将
/path/to/extend_expiring_tokens.rb更改为您的extend_expiring_tokens.rb文件的完整路径:sudo gitlab-rails runner /path/to/extend_expiring_tokens.rb
有关更多信息,请参阅 Rails Runner 故障排除部分。
extend_expiring_tokens.rb
expiring_date = Date.new(2024, 5, 30)
new_expires_at = 6.months.from_now
total_updated = PersonalAccessToken
.not_revoked
.without_impersonation
.where(expires_at: expiring_date.to_date)
.update_all(expires_at: new_expires_at.to_date)
puts "已更新 #{total_updated} 个令牌,新的过期日期为 #{new_expires_at}"识别在特定日期过期的个人、项目和群组访问令牌
没有过期日期的访问令牌将无限期有效,如果访问令牌泄露,这会带来安全风险。
为管理此风险,当您升级到 GitLab 16.0 及更高版本时,任何 个人、 项目 或 群组 访问 令牌如果没有过期日期,将自动设置一个在升级日期一年后到期的过期日期。
在 GitLab 17.3 及更高版本中,此对现有令牌的自动过期设置已被撤销,您可以为新访问令牌禁用过期日期强制执行。
如果您不知道令牌何时过期,因为日期已更改,您可能会在尝试在该日期登录 GitLab 时遇到意外的身份验证失败。
为解决此问题,您应该升级到 GitLab 17.2 或更高版本,因为这些版本包含一个帮助分析、延长或删除令牌过期日期的工具。
如果您无法运行该工具,也可以在 GitLab 自托管实例中运行脚本来识别以下令牌:
- 在特定日期过期的令牌。
- 没有过期日期的令牌。
您可以在以下环境中从终端窗口运行这些脚本:
- Rails 控制台会话。
- 使用 Rails Runner。
您运行的具体脚本取决于您是否已升级到 GitLab 16.0 及更高版本:
- 如果您尚未升级到 GitLab 16.0 或更高版本,请识别没有过期日期的令牌。
- 如果您已升级到 GitLab 16.0 或更高版本,使用脚本来识别以下任何内容:
在您识别出受此问题影响的令牌后,如果需要,您可以运行最终脚本来延长特定令牌的有效期。
这些脚本返回以下格式的结果:
群组 ID 25 中的过期群组访问令牌,令牌 ID: 8,名称:示例令牌,范围:["read_api", "create_runner"],最后使用时间:
项目 ID 2 中的过期项目访问令牌,令牌 ID: 9,名称:测试令牌,范围:["api", "read_registry", "write_registry"],最后使用时间:2022-02-11 13:22:14 UTC有关更多信息,请参阅事件 18003。
查找在特定日期过期的所有令牌
此脚本查找在特定日期过期的令牌。
先决条件:
- 您必须知道您的实例升级到 GitLab 16.0 的确切日期。
要使用它:
- 在您的终端窗口中,连接到您的实例。
- 使用
sudo gitlab-rails console启动 Rails 控制台会话。 - 根据您的需要,从下一节复制整个
expired_tokens.rb或从下一节复制expired_tokens_date_range.rb脚本, 并将其粘贴到控制台中。 将expires_at_date更改为您的实例升级到 GitLab 16.0 一年后的日期。 - 按 Enter。
-
在您的终端窗口中,连接到您的实例。
-
根据您的需要,从下一节复制整个
expired_tokens.rb或从下一节复制expired_tokens_date_range.rb脚本, 并将其保存为实例上的文件:- 将其命名为
expired_tokens.rb。 - 将
expires_at_date更改为您的实例升级到 GitLab 16.0 一年后的日期。 - 文件必须对
git:git可访问。
- 将其命名为
-
运行以下命令,将路径更改为您的
expired_tokens.rb文件的完整路径:sudo gitlab-rails runner /path/to/expired_tokens.rb
有关更多信息,请参阅 Rails Runner 故障排除部分。
expired_tokens.rb
此脚本要求您知道您的 GitLab 实例升级到 GitLab 16.0 的确切日期。
# 将此值更改为您的 GitLab 实例升级后一年的日期。
expires_at_date = "2024-05-22"
# 检查即将过期的个人访问令牌
PersonalAccessToken.owner_is_human.where(expires_at: expires_at_date).find_each do |token|
if token.user.blocked?
next
# 从输出中隐藏不可用、被阻止的 PAT
end
puts "过期的个人访问令牌 ID: #{token.id}, 用户邮箱: #{token.user.email}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
# 检查即将过期的项目和群组访问令牌
PersonalAccessToken.project_access_token.where(expires_at: expires_at_date).find_each do |token|
token.user.members.each do |member|
type = member.is_a?(GroupMember) ? '群组' : '项目'
puts "#{type} ID #{member.source_id} 中的过期 #{type} 访问令牌,令牌 ID: #{token.id}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
end要隐藏并删除属于被阻止用户的令牌,在 if token.user.blocked? 正下方直接添加 token.destroy!。但是,此操作不会留下审计事件,不像API 方法。
查找在给定月份过期的令牌
此脚本查找在特定月份过期的令牌。您不需要知道您的实例升级到 GitLab 16.0 的确切日期。要使用它:
- 在您的终端窗口中,使用
sudo gitlab-rails console启动 Rails 控制台会话。 - 从下一节粘贴整个
expired_tokens_date_range.rb脚本。 如果需要,可以将date_range更改为不同的范围。 - 按 Enter。
-
在您的终端窗口中,连接到您的实例。
-
从下一节复制整个
expired_tokens_date_range.rb脚本,并将其保存为实例上的文件:- 将其命名为
expired_tokens_date_range.rb。 - 如果需要,可以将
date_range更改为不同的范围。 - 文件必须对
git:git可访问。
- 将其命名为
-
运行以下命令,将
/path/to/expired_tokens_date_range.rb更改为您的expired_tokens_date_range.rb文件的完整路径:sudo gitlab-rails runner /path/to/expired_tokens_date_range.rb
有关更多信息,请参阅 Rails Runner 故障排除部分。
expired_tokens_date_range.rb
# 此脚本使您能够搜索在特定日期范围内(如 1.month)从当前日期到期的令牌。
如果您不确定 GitLab 16.0 升级完成的确切时间,请使用它。
date_range = 1.month
# 检查个人访问令牌
PersonalAccessToken.owner_is_human.where(expires_at: Date.today .. Date.today + date_range).find_each do |token|
puts "过期的个人访问令牌 ID: #{token.id}, 用户邮箱: #{token.user.email}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
# 检查即将过期的项目和群组访问令牌
PersonalAccessToken.project_access_token.where(expires_at: Date.today .. Date.today + date_range).find_each do |token|
token.user.members.each do |member|
type = member.is_a?(GroupMember) ? '群组' : '项目'
puts "#{type} ID #{member.source_id} 中的过期 #{type} 访问令牌,令牌 ID: #{token.id}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
end识别许多令牌过期的日期
此脚本识别大多数令牌过期的日期。您可以将其与页面上的其他脚本结合使用,以识别和延长可能接近其过期日期的大量令牌,以防您的团队尚未设置令牌轮换。
该脚本返回以下格式的结果:
42 个个人访问令牌将于 2024-06-27 过期
17 个个人访问令牌将于 2024-09-23 过期
3 个个人访问令牌将于 2024-08-13 过期要使用它:
- 在您的终端窗口中,使用
sudo gitlab-rails console启动 Rails 控制台会话。 - 粘贴整个
dates_when_most_of_tokens_expire.rb脚本。 - 按 Enter。
-
在您的终端窗口中,连接到您的实例。
-
复制整个
dates_when_most_of_tokens_expire.rb脚本,并将其保存为实例上的文件:- 将其命名为
dates_when_most_of_tokens_expire.rb。 - 文件必须对
git:git可访问。
- 将其命名为
-
运行以下命令,将
/path/to/dates_when_most_of_tokens_expire.rb更改为您的dates_when_most_of_tokens_expire.rb文件的完整路径:sudo gitlab-rails runner /path/to/dates_when_most_of_tokens_expire.rb
有关更多信息,请参阅 Rails Runner 故障排除部分。
dates_when_most_of_tokens_expire.rb
PersonalAccessToken
.select(:expires_at, Arel.sql('count(*)'))
.where('expires_at >= NOW()')
.group(:expires_at)
.order(Arel.sql('count(*) DESC'))
.limit(10)
.each do |token|
puts "#{token.count} 个个人访问令牌将于 #{token.expires_at} 过期"
end查找没有过期日期的令牌
此脚本查找没有过期日期的令牌:expires_at 为 NULL。对于尚未升级到 GitLab 16.0 或更高版本的用户,令牌的 expires_at 值为 NULL,可用于识别需要添加过期日期的令牌。
您可以在 Rails 控制台 或 Rails Runner 中使用此脚本:
- 在您的终端窗口中,连接到您的实例。
- 使用
sudo gitlab-rails console启动 Rails 控制台会话。 - 从下一节粘贴整个
tokens_with_no_expiry.rb脚本。 - 按 Enter。
-
在您的终端窗口中,连接到您的实例。
-
从下一节复制整个
tokens_with_no_expiry.rb脚本,并将其保存为实例上的文件:- 将其命名为
tokens_with_no_expiry.rb。 - 文件必须对
git:git可访问。
- 将其命名为
-
运行以下命令,将路径更改为您的
tokens_with_no_expiry.rb文件的完整路径:sudo gitlab-rails runner /path/to/tokens_with_no_expiry.rb
有关更多信息,请参阅 Rails Runner 故障排除部分。
tokens_with_no_expiry.rb
此脚本查找没有为 expires_at 设置值的令牌。
# 此脚本查找未设置 expires_at 值的令牌。
# 检查即将过期的个人访问令牌
PersonalAccessToken.owner_is_human.where(expires_at: nil).find_each do |token|
puts "个人访问令牌 ID #{token.id} 的 expires_at 为 nil,用户邮箱: #{token.user.email}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
# 检查即将过期的项目和群组访问令牌
PersonalAccessToken.project_access_token.where(expires_at: nil).find_each do |token|
token.user.members.each do |member|
type = member.is_a?(GroupMember) ? '群组' : '项目'
puts "#{type} ID #{member.source_id} 中的 #{type} 访问令牌的 expires_at 为 nil,令牌 ID: #{token.id}, 名称: #{token.name}, 范围: #{token.scopes}, 最后使用时间: #{token.last_used_at}"
end
end