Help us learn about your current experience with the documentation. Take the survey.

自动响应泄露的密钥

  • 版本:Ultimate
  • 提供方式:GitLab.com、GitLab 自托管、GitLab 专用

GitLab 密钥检测在发现某些类型的泄露密钥时会自动响应。 自动响应可以:

  • 自动撤销密钥。
  • 通知签发密钥的合作伙伴。合作伙伴随后可以撤销密钥、通知其所有者,或采取其他措施防止滥用。

支持的密钥类型和操作

GitLab 支持对以下类型的密钥进行自动响应:

密钥类型 执行的操作 在 GitLab.com 上支持 在 GitLab 自托管中支持
GitLab personal access tokens 立即撤销令牌,向所有者发送电子邮件 15.9 及更高版本
Amazon Web Services (AWS) IAM access keys 通知 AWS
Google Cloud service account keysAPI keysOAuth client secrets 通知 Google Cloud
Postman API keys 通知 Postman;Postman 通知密钥所有者

组件图例

  • ✅ - 默认可用
  • ⚙ - 需要使用令牌撤销 API 进行手动集成

功能可用性

凭据仅在密钥检测发现它们时进行后处理:

  • 在公共项目中,因为公开暴露的凭据构成更大的威胁。扩展到私有项目正在问题 391379中考虑。
  • 在具有 GitLab Ultimate 的项目中,出于技术原因。扩展到所有版本在问题 391763中跟踪。

高级架构

此图表描述了后处理钩子如何在 GitLab 应用程序中撤销密钥:

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: 架构图
accDescr: 后处理钩子如何在 GitLab 应用程序中撤销密钥。

    autonumber
    GitLab Rails-->+GitLab Rails: gl-secret-detection-report.json
    GitLab Rails->>+GitLab Sidekiq: StoreScansService
    GitLab Sidekiq-->+GitLab Sidekiq: ScanSecurityReportSecretsWorker
    GitLab Sidekiq-->+GitLab Token Revocation API: GET revocable keys types
    GitLab Token Revocation API-->>-GitLab Sidekiq: OK
    GitLab Sidekiq->>+GitLab Token Revocation API: POST revoke revocable keys
    GitLab Token Revocation API-->>-GitLab Sidekiq: ACCEPTED
    GitLab Token Revocation API-->>+Partner API: revoke revocable keys
    Partner API-->>+GitLab Token Revocation API: ACCEPTED
  1. 包含密钥检测任务的流水线完成,生成扫描报告(1)。
  2. 报告由服务类处理(2),如果可以撤销令牌,则安排异步工作器。
  3. 异步工作器(3)与外部部署的 HTTP 服务(45)通信,以确定哪些类型的密钥可以自动撤销。
  4. 工作器发送(67)检测到的密钥列表,GitLab 令牌撤销 API 可以撤销这些密钥。
  5. GitLab 令牌撤销 API 将(89)每个可撤销的令牌发送到其各自供应商的合作伙伴 API

泄露凭据通知的合作伙伴计划

当 GitLab.com 上的公共仓库中泄露了合作伙伴签发的凭据时,GitLab 会通知合作伙伴。 如果您运营云或 SaaS 产品,并且有兴趣接收这些通知,请在史诗 4944中了解更多信息。 合作伙伴必须实现合作伙伴 API,该 API 由 GitLab 令牌撤销 API 调用。

实现合作伙伴 API

合作伙伴 API 与 GitLab 令牌撤销 API 集成,以接收和响应泄露的令牌撤销请求。该服务应该是幂等和速率限制的公开可访问的 HTTP API。

对您服务的请求可以包含一个或多个泄露的令牌,以及带有请求正文签名的标头。我们强烈建议您使用此签名验证传入请求,以证明它是来自 GitLab 的真实请求。下图详细说明了接收、验证和撤销泄露令牌的必要步骤:

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: 合作伙伴 API 数据流
accDescr: 合作伙伴 API 应如何接收和响应泄露的令牌撤销请求。

    autonumber
    GitLab Token Revocation API-->>+Partner API: 发送新的泄露凭据
    Partner API-->>+GitLab Public Keys endpoint: 获取活跃的公钥
    GitLab Public Keys endpoint-->>+Partner API: 一个或多个公钥
    Partner API-->>+Partner API: 验证请求是否由 GitLab 签名
    Partner API-->>+Partner API: 响应泄露
    Partner API-->>+GitLab Token Revocation API: HTTP 状态
  1. GitLab 令牌撤销 API 向合作伙伴 API 发送(1撤销请求。请求包含包含公钥标识符和请求正文签名的标头。
  2. 合作伙伴 API 向 GitLab 请求(2公钥列表。响应(3)在密钥轮换的情况下可能包含多个公钥,应使用请求标头中的标识符进行过滤。
  3. 合作伙伴 API 使用公钥(4验证签名与实际请求正文。
  4. 合作伙伴 API 处理泄露的令牌,这可能涉及自动撤销(5)。
  5. 合作伙伴 API 使用适当的 HTTP 状态代码(6)响应 GitLab 令牌撤销 API:
    • 成功的响应代码(HTTP 200 到 299)确认合作伙伴已收到并处理了请求。
    • 错误代码(HTTP 400 或更高)会导致 GitLab 令牌撤销 API 重试请求。

撤销请求

此 JSON 架构文档描述了撤销请求的正文:

{
    "type": "array",
    "items": {
        "description": "一个泄露的令牌",
        "type": "object",
        "properties": {
            "type": {
                "description": "令牌类型。这是供应商特定的,可以根据您的撤销服务进行自定义",
                "type": "string",
                "examples": [
                    "my_api_token"
                ]
            },
            "token": {
                "description": "被密钥检测分析器匹配的子字符串。在大多数情况下,这是令牌本身",
                "type": "string",
                "examples": [
                    "XXXXXXXXXXXXXXXX"
                ]
            },
            "url": {
                "description": "托管在 GitLab 上的泄露令牌所在原始源文件的 URL",
                "type": "string",
                "examples": [
                    "https://gitlab.example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"
                ]
            }
        }
    }
}

示例:

[{"type": "my_api_token", "token": "XXXXXXXXXXXXXXXX", "url": "https://example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"}]

在此示例中,密钥检测已确定 my_api_token 的实例已泄露。除了包含泄露令牌的文件的原始内容的公开可访问 URL 外,令牌的值也提供给您。

请求包含两个特殊标头:

标头 类型 描述
Gitlab-Public-Key-Identifier string 用于签名此请求的密钥对的唯一标识符。主要用于辅助密钥轮换。
Gitlab-Public-Key-Signature string 请求正文的 base64 编码签名。

您可以使用这些标头以及 GitLab 公钥端点来验证撤销请求的真实性。

公钥端点

GitLab 维护一个公开可访问的端点,用于检索用于验证撤销请求的公钥。该端点可以根据请求提供。

此 JSON 架构文档描述了公钥端点的响应正文:

{
    "type": "object",
    "properties": {
        "public_keys": {
            "description": "由 GitLab 管理的用于签名令牌撤销请求的公钥数组。",
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "key_identifier": {
                        "description": "密钥对的唯一标识符。将其与 Gitlab-Public-Key-Identifier 标头的值匹配",
                        "type": "string"
                    },
                    "key": {
                        "description": "公钥的值",
                        "type": "string"
                    },
                    "is_current": {
                        "description": "密钥当前是否活跃并正在签名新请求",
                        "type": "boolean"
                    }
                }
            }
        }
    }
}

示例:

{
    "public_keys": [
        {
            "key_identifier": "6917d7584f0fa65c8c33df5ab20f54dfb9a6e6ae",
            "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN05/VjsBwWTUGYMpijqC5pDtoLEf\nuWz2CVZAZd5zfa/NAlSFgWRDdNRpazTARndB2+dHDtcHIVfzyVPNr2aznw==\n-----END PUBLIC KEY-----\n",
            "is_current": true
        }
    ]
}

验证请求

您可以通过使用从上述 API 响应中获取的相应公钥验证 Gitlab-Public-Key-Signature 标头与请求正文,来检查撤销请求的真实性。我们使用带有 SHA256 哈希的 ECDSA 生成签名,然后将签名 base64 编码到标头值中。

下面的 Python 脚本演示了如何验证签名。它使用流行的 pyca/cryptography 模块进行加密操作:

import hashlib
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives.asymmetric import ec

public_key = str.encode("")      # 从公钥端点获取
signature_header = ""            # 从 `Gitlab-Public-Key-Signature` 标头获取
request_body = str.encode(r'')   # 从撤销请求正文获取

pk = load_pem_public_key(public_key)
decoded_signature = base64.b64decode(signature_header)

pk.verify(decoded_signature, request_body, ec.ECDSA(hashes.SHA256()))  # 失败时抛出异常

print("签名验证成功!")

主要步骤是:

  1. 将公钥加载到适合您使用的加密库的格式中。
  2. Base64 解码 Gitlab-Public-Key-Signature 标头值。
  3. 使用 SHA256 哈希指定 ECDSA 来验证正文与解码的签名。