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

云连接器

GitLab 云连接器(Cloud Connector)是一种访问多个 GitLab 部署、实例和单元格共同使用的服务的方式。目前,云连接器本身并不是一个独立的服务,而是一组 API 和代码,用于标准化将基于云的服务与 GitLab 实例集成时的身份验证和其他事项的方法。本页旨在解释如何使用云连接器将 GitLab Rails 与服务链接起来。

有关云连接器的更多信息,请参阅架构页面。有关文档中使用的术语列表,请参阅术语。另请参阅配置了解付费功能如何打包到 GitLab 版本和附加组件中的信息。

教程:使用云连接器连接新功能

以下部分将涵盖以下用例:

通过现有的后端服务引入新功能

Ai Gateway 目前是唯一连接到云连接器的后端服务。 要将新功能添加到现有的后端服务(Ai Gateway)中:

  1. 在 JWT 签发者中注册新功能
  2. 在 GitLab Rails 中实现权限检查
  3. 在后端服务中实现授权检查

可选: 如果令牌用于的后端服务需要在服务访问令牌中嵌入额外的声明,请联系 #f_cloud_connector(仅限内部 Slack),因为我们目前没有自助服务的接口来处理此操作。

在 JWT 签发者中注册新功能

  • 对于 GitLab Dedicated 和 GitLab Self-Managed,CustomersDot 是 JWT 签发者
  • 对于 GitLab.com 部署,GitLab.com 是 JWT 签发者,因为它能够为每个到云连接器功能的请求自签名并创建 JWT

为 GitLab Self-Managed、Dedicated 和 GitLab.com 客户注册新功能

您必须将新功能作为单元原语(unit primitive)注册到 gitlab-cloud-connector 仓库中。 该仓库是所有云连接器配置的单一事实来源(SSoT)。

要注册新功能:

  1. gitlab-cloud-connector 仓库的 config/unit_primitives/ 目录中创建一个新的 YAML 文件。
  2. 定义单元原语配置,并确保遵循架构

例如,要添加一个名为 new_feature 的新功能:

# config/unit_primitives/new_feature.yml
---
name: new_feature
description: 新功能的描述
cut_off_date: 2024-10-17T00:00:00+00:00  # 可选,如果不是免费功能则设置
min_gitlab_version: '16.9'
min_gitlab_version_for_free_access: '16.8' # 可选
group: group::your_group
feature_category: your_category
documentation_url: https://docs.gitlab.com/ee/path/to/docs
backend_services:
    - ai_gateway
add_ons:
    - duo_pro
    - duo_enterprise
license_types:
    - premium
    - ultimate
向后兼容性

对于仍在使用旧遗留结构的实例,考虑将您的单元原语也添加到服务配置中。

  • 如果单元原语是独立功能,则无需进一步更改,同名的服务将自动生成。
  • 如果单元原语作为现有服务的一部分提供,如 duo_chatself_hosted_modelsvertex_ai_proxy,请将单元原语添加到 config/services 目录中的所需服务中。
部署流程

请遵循我们的发布清单来发布库的新版本并在 GitLab 项目中使用它。

在 GitLab Rails 中实现权限检查

新功能作为独立服务提供
访问令牌

例如,该功能作为名为 new_feature 的独立服务提供。

  1. 调用 CloudConnector::AvailableServices.find_by_name(:new_feature).access_token(user_or_namespace) 并将此令牌包含在 Authorization HTTP 头字段中。

    • 在 GitLab.com 上,它将根据提供的资源自签发具有相应范围的令牌:
      • 对于用户:范围将基于用户的席位分配
      • 对于命名空间:范围将基于该命名空间购买的附加组件
        • 如果服务可以免费访问,令牌将包含该服务的所有可用范围。
        • 对于 Duo Chat,JWT 将包含 documentation_searchduo_chat 范围。
    • 在 GitLab Self-Managed 上,它将始终返回 ::CloudConnector::ServiceAccessToken JWT 令牌。
      • 对于 GitLab Self-Managed 实例,提供的用户、命名空间或额外声明参数将被忽略。 请参阅本节了解如何处理 GitLab Self-Managed 实例的自定义声明。

    后端服务(AI 网关)在接收请求时必须验证此令牌及其携带的任何范围。

  2. 如果您需要在令牌中嵌入特定于用例的额外声明,可以在 extra_claims 参数中传递这些声明。

  3. 确保您的请求将所需的头发送到后端服务

    这些头可以在 gitlab-cloud-connector README 中找到。

    其中一些头可以通过将 ::CloudConnector#headers 方法的结果合并到您的负载中来注入。 对于 AI 用例和针对 AI 网关的请求,请改用 ::CloudConnector#ai_headers

权限检查

要决定服务是否可用或对最终用户可见,我们需要:

  • 可选。在 GitLab Self-Managed 上,如果新功能作为新的企业功能引入, 请按照EE 功能指南检查用户是否有权访问该功能。

      next true if ::Gitlab::Saas.feature_available?(:new_feature_on_saas)
    
      ::License.feature_available?(:new_feature)
  • 在 GitLab Self-Managed 上,检查客户是否使用在线云许可证

    • 云连接器目前仅支持 GitLab Self-Managed 客户的在线云许可证。
    • 不支持试用版或遗留许可证。
    • GitLab.com 使用的是遗留许可证。
      ::License.current&.online_cloud_license?
  • 可选。如果服务有免费访问权限,这通常意味着实验性功能受测试协议约束。

    • 对于 GitLab Duo 功能,客户需要启用实验性开关才能免费使用实验性功能。
  • 在 GitLab.com 和 GitLab Self-Managed 上,检查客户的最终用户是否已分配到适当的席位。

      # 如果允许使用服务,则返回 true。
      #
      # 对于提供的用户,将检查用户是否已分配到适当的席位。
      current_user.allowed_to_use?(:new_feature)
示例

以下示例是对名为 :new_feature 的服务的请求。 这里我们假设您的后端服务名为 foo,并且已经在 https://cloud.gitlab.com/foo 上可访问。 我们还假设后端服务使用 /new_feature_endpoint 端点暴露该服务。 这允许客户端在 https://cloud.gitlab.com/foo/new_feature_endpoint 访问该服务。

ee/global_policy.rb 中添加新的策略规则:

  condition(:new_feature_licensed) do
    next true if ::Gitlab::Saas.feature_available?(:new_feature_on_saas)
    next false unless ::License.current.online_cloud_license?

    ::License.feature_available?(:new_feature)
  end

  condition(:user_allowed_to_use_new_feature) do
    @user.allowed_to_use?(:new_feature)
  end

  rule { new_feature_licensed & user_allowed_to_use_new_feature }.enable :access_new_feature

请求

include API::Helpers::CloudConnector

# 根据席位分配、附加组件购买情况检查服务是否对给定用户可用
return unauthorized! unless current_user.can?(:access_new_feature)

# 对于 Gitlab.com,它将根据提供的资源自签发具有相应范围的令牌:
# - 对于提供的用户,将根据用户分配权限自签发令牌
# - 对于提供的命名空间,将根据附加组件购买权限自签发令牌
#
# 对于 SM,将返回 :CloudConnector::ServiceAccessToken 实例令牌,忽略提供的用户、命名空间和额外声明
token = ::CloudConnector::AvailableServices.find_by_name(:new_feature).access_token(current_user)

Gitlab::HTTP.post(
  "https://cloud.gitlab.com/foo/new_feature_endpoint",
  headers: {
      'Authorization' => "Bearer #{token}",
    }.merge(cloud_connector_headers(current_user))
)

引入的策略可用于控制前端是否可见。添加一个 new_feature_helper.rb

  def show_new_feature?
      current_user.can?(:access_new_feature)
  end
新功能作为现有服务的一部分提供(Duo Chat)
访问令牌

如果功能作为现有服务的一部分提供,如 Duo Chat, 调用 CloudConnector::AvailableServices.find_by_name(:duo_chat).access_token(user_or_namespace) 将返回一个 IJWT, 其中包含所有授权功能(单元原语)的访问范围。

如果令牌范围未包含在 JWT 中,后端服务(AI 网关)将阻止访问特定功能(单元原语)。

权限检查

如果功能作为现有服务的一部分提供,如 Duo Chat,则不需要额外的权限检查。

我们可以依赖现有的全局策略规则 user.can?(:access_duo_chat)。 如果最终用户有权访问至少一个功能(单元原语),则最终用户可以访问该服务。 对单个功能(单元原语)的访问权限由 IJWT 范围控制,将由 后端服务(Ai Gateway)验证。 请参阅访问令牌

在后端服务中实现授权检查

GitLab Rails 调用后端服务来提供 GitLab Self-Managed 和 Dedicated 实例原本无法使用的功能。为了使 GitLab Rails 能够调用此功能,必须暴露一个端点。 后端服务必须验证 GitLab Rails 在 Authorization 头中发送的每个 JWT。

有关 AI 网关授权过程的更多信息及示例,请参阅AI 网关授权文档

通过新的后端服务引入新功能

要集成一个云连接器功能尚未访问的新后端服务:

  1. 设置 JWT 验证
  2. 使其在 cloud.gitlab.com 上可用

设置 JWT 验证

在后端服务中实现授权检查中所述,对于已经使用云连接器的服务, 每个服务必须验证 GitLab 实例发送的 JWT 是否合法。

为此,后端服务必须:

  1. 维护 JSON Web Key Set (JWKS)
  2. 使用此集中的密钥验证 JWT

有关此机制背后的详细解释,请参阅架构:访问控制

我们强烈建议使用现有的软件库来处理 JWKS 和 JWT 身份验证。 示例包括:

维护用于令牌验证的 JWKS

JWT 在首次签发时由令牌颁发机构进行加密签名。 GitLab 实例随后将 JWT 附加在对后端服务发出的请求中。

为了验证 JWT 服务访问令牌,后端服务必须首先获取包含与用于签名令牌的私钥对应的公钥验证密钥的 JWKS。 由于 GitLab.com 和 CustomersDot 都会签发令牌,后端服务必须从两者获取 JWKS。

要获取 JWKS,请使用 GitLab.com 和 CustomersDot 暴露的 OIDC 发现端点。 对于每个令牌颁发机构:

  1. GET /.well-known/openid-configuration

    示例响应:

    {
      "issuer": "https://customers.gitlab.com/",
      "jwks_uri": "https://customers.gitlab.com/oauth/discovery/keys",
      "id_token_signing_alg_values_supported": [
        "RS256"
      ]
    }
  2. GET <jwks_uri>

    示例响应:

    {
      "keys": [
        {
          "kty": "RSA",
          "n": "sGy_cbsSmZ_Y4XV80eK_ICmz46XkyWVf6O667-mhDcN5FcSfPW7gqhyn7s052fWrZYmJJZ4PPyh6ZzZ_gZAaQM7Oe2VrpbFdCeJW0duR51MZj52FwShLfi-NOBz2GH9XuUsRBKnXt7wwKQTabH4WW7XL23Hi0eDjc9dyQmsr2-AbH05yVsrgvEYSsWiCGEgobPgNc51DwBoIcsJ-kFN591aO_qAkbpf1j7yAuAVG7TUxaditQhyZKkourPXXyx1R-u0Lx9UJyAV8ySqFxq3XDE_pg6ZuJ7M0zS0XnGI82g3Js5zAughrQyJMhKd8j5c8UfSGxhRBQh58QNl3UwoMjQ",
          "e": "AQAB",
          "kid": "ZoObkdsnUfqW_C_EfXp9DM6LUdzl0R-eXj6Hrb2lrNU",
          "use": "sig",
          "alg": "RS256"
        }
      ]
    }
  3. 缓存响应。我们建议让缓存一天后过期。

通过这种方式获得的密钥可用于验证由相应令牌颁发机构签发的 JWT。 具体如何操作取决于所使用的编程语言和库。一般说明可以在定位 JSON Web Key Sets中找到。 后端服务可以将来自两个令牌颁发机构的响应合并到一个缓存的结果集中。

使用 JWKS 验证 JWT

要验证 JWT:

  1. 从 HTTP Authorization 头中读取令牌字符串。
  2. 使用 JWT 库对象和先前获取的 JWKS 进行验证。

验证令牌时,确保:

  1. 令牌签名正确。
  2. aud 声明等于或包含后端服务(该字段可以是字符串或数组)。
  3. iss 声明与用于验证它的密钥的颁发者 URL 匹配。
  4. scopes 声明涵盖请求端点暴露的功能(请参阅在后端服务中实现授权检查)。

添加新的云连接器路由

所有云连接器功能必须通过 cloud.gitlab.com 访问,这是一个全局负载均衡器, 根据路径前缀将请求路由到后端服务。例如,AI 功能必须从 cloud.gitlab.com/ai/<AI-specific-path> 请求。 然后负载均衡器将 <AI-specific-path> 路由到 AI 网关。

要将新后端服务连接到云连接器,您必须声明一个新的路径前缀来将请求路由到您的服务。 例如,如果您连接 foo-service,必须添加一个新路由,将 cloud.gitlab.com/foo 路由到 foo-service

添加新路由需要访问生产基础设施配置。如果您需要添加新路由,请在 gitlab-org/gitlab 问题跟踪器中创建一个问题,并将其分配给 Runway 组。

测试

有关如何设置与 AI 网关作为后端服务的端到端集成的示例,请参见此处