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

Cloud Connector: 架构

GitLab Cloud Connector 是一种访问多个 GitLab 部署、实例和单元格共同服务的途径。目前,Cloud Connector 本身并不是一个独立的服务,而是一组 API 和代码,用于标准化基于云的服务与 GitLab 实例集成时的认证和其他事项处理方式。

本页介绍 Cloud Connector 的总体架构,作为主要开发者文档的补充资源阅读。

术语

在讨论 Cloud Connector 的组成部分和工作机制时,我们使用以下术语:

  • GitLab Rails: 主要的 GitLab 应用程序。
  • GitLab.com: 由 GitLab Inc. 运营的多租户 GitLab SaaS 部署。
  • GitLab Dedicated: 由 GitLab Inc. 运营的单租户 GitLab SaaS 部署。
  • GitLab Self-Managed: 由客户运营的任何 GitLab 实例,可能部署在私有云中。
  • GitLab instance: 上述任何一种。
  • Backend service: 由 GitLab 运营的 Web 服务,由 GitLab 实例调用,以提供属于 Cloud Connector 功能集的功能。AI 网关就是一个例子。
  • CustomersDot: GitLab 客户门户,客户用于管理其 GitLab 订阅。
  • OIDC: OpenID Connect,一个用于实现身份提供者和身份验证/授权的开放标准。JWT 发行者提供符合 OIDC 的发现端点,以发布 JWT 验证器的密钥。
  • JWT: JSON Web Token,一种开放标准,用于以加密签名令牌的形式编码和传输身份数据。此令牌用于授权 GitLab 实例或用户与后端服务之间的请求。它可以限定为 GitLab 实例或用户。
  • JWT issuer: 由 GitLab 运营的 Web 服务,提供发行 JWT 的端点。OAuth 规范将其称为 Authorization Server。和/或提供验证此类令牌所需的公钥的端点。GitLab.com、CustomersDot 和 AI 网关都是 JWT 发行者。
  • JWT validator: 一个后端服务,使用从 JWT 发行者获得的公钥验证携带 JWT 的 GitLab 实例请求。OAuth 规范将其称为 Resource Server。AI 网关是 JWT 验证器的一个例子。
  • IJWT: 实例 JSON Web Token,为 GitLab 实例创建的 JWT。
  • UJWT: 用户 JSON Web Token,为 GitLab 用户创建的 JWT,生命周期较短,权限少于 IJWT。
  • JWKS: JSON Web Key Set,一种开放标准,用于编码验证 JWT 的加密密钥。
  • Unit primitives: 权限/访问范围可以管理的逻辑功能。
  • Add-On: 捆绑在一起销售的一组单元原语。例如:code_suggestionsduo_chat 是在 DUO_PRO 插件下一起销售的 2 个 UP。

要解决的问题

大多数 GitLab 功能可以直接从 GitLab 实例提供,无论其部署位置如何。然而,某些功能需要第三方供应商集成,或在 GitLab.com 之外难以操作。这给 GitLab Self-Managed 和 GitLab Dedicated 客户带来了问题,因为他们无法轻松访问这些功能。

Cloud Connector 通过以下方式解决这个问题:

  • 将功能从 GitLab Rails 移至 GitLab 运营的服务,使客户免于手动配置和操作它们的麻烦。
  • cloud.gitlab.com 提供进入 Cloud Connector 功能的全局入口点,以访问后端服务。
  • 将实例许可证和计费数据连接到访问授权,使 GitLab 实例能够消耗由 GitLab Inc. 运营的后端服务中托管的功能。

Cloud Connector 组件

从技术上讲,Cloud Connector 由以下部分组成:

  1. 全局负载均衡器。 通过 Cloudflare 托管在 cloud.gitlab.com,所有进入 Cloud Connector 功能(如 AI)的流量都必须通过此主机。负载均衡器基于路径前缀进行路由决策。例如:
    1. 负载均衡器将 /prefix 映射到后端服务。
    2. 客户端请求 cloud.gitlab.com/prefix/path
    3. 负载均衡器剥离 /prefix 并将 /path 路由到后端服务。
  2. 选择 GitLab.com 和 CustomersDot 作为 IJWT 发行者。 我们使用只有 GitLab Inc. 可以访问的私钥配置这些部署。我们使用这些密钥发行加密签名的 IJWT,GitLab Rails 实例可以使用它向连接的服务后端发出上游请求。公钥验证密钥通过 OIDC 发现 API 端点发布。
  3. 选择 AI 网关作为 UJWT 发行者和验证者。 与上述 IJWT 发行者类似,但目的是仅为用户发行令牌。AI 网关是其自身的验证者,因此验证密钥不会发布在 OIDC 发现 API 端点上。
  4. 选择后端服务作为 IJWT 验证者。 后端服务定期与 GitLab.com 或 CustomersDot 同步,以获取用于验证附加到请求的服务令牌签名的公钥。然后,后端服务可以根据签名有效性以及令牌正文可能携带的任何声明来决定接受或拒绝请求。
  5. 编程 API 以与上述内容集成。 我们旨在 Ruby 中提供必要的接口,以便更容易实现 GitLab Rails 应用程序和后端服务之间的通信。这是一个不断发展的目标,我们将问题提交到 Cloud Connector 抽象史诗 中以改进这一点。

下图概述了这些组件如何交互:

@startuml

node "Cloudflare" {
  [cloud.gitlab.com] as LB #yellow
}

node "GitLab SaaS" {
  package "Backend service deployments" as BACK {
    [Backend 1] as BE1
    [Backend 2] as BE2
  }

  package "OIDC providers" as OIDC {
    [GitLab.com] as DOTCOM
    [Customers Portal] as CDOT
  }

  package "GitLab Dedicated" as DED {
     [GitLab instance 1]
     [GitLab instance 2]
  }
}

node "Customer deployments" {
  [GitLab instance] as SM
}

BACK -down-> OIDC : "OIDC discovery"

DOTCOM -right-> LB : "request /prefix"
LB -left-> BACK: " route /prefix to backend"

SM -up-> LB : " request /prefix"
SM <-up-> CDOT : "sync access data"
DED <-up-> CDOT : "sync access data"

@enduml

访问控制

向后端服务发出请求时有两个级别的访问控制:

  1. 实例访问。 通过发行绑定到客户云许可证计费状态的 IJWT 来授予特定的 Self-Managed/Dedicated 实例访问权限。此令牌每天从 CustomersDot 同步到 GitLab 实例并存储在实例的本地数据库中。对于 GitLab.com,我们不需要此步骤;相反,我们为每个请求发行短期令牌。这些令牌实现为 JWT,并由发行者进行加密签名。
  2. 用户访问。 我们目前期望所有最终用户请求至少先通过相应的 GitLab 实例一次。对于某些请求(例如代码补全),我们允许用户使用限定于后端的 UJWT 直接向后端服务发出请求。此令牌的生命周期和访问权限比实例令牌更有限。要获取用户令牌,用户首先需要通过相应的 GitLab 实例请求令牌。因此,用户级别的身份验证和授权处理方式与任何 REST 或 GraphQL API 请求相同,即使用 OAuth 或个人访问令牌。

用于实例访问的 JWT 包含以下声明(非详尽,可能变更):

  • aud: 受众。这是后端服务的名称(例如:gitlab-ai-gateway)。
  • sub: 主题。这是发行令牌的 GitLab 实例的 UUID(例如:8f6e4253-58ce-42b9-869c-97f5c2287ad2)。
  • iss: 发行者 URL。可以是 https://gitlab.comhttps://customers.gitlab.com
  • exp: 令牌的过期时间(UNIX 时间戳)。目前 GitLab.com 为 1 小时,Self-Managed/Dedicated 为 3 天。
  • nbf: 此令牌在此时间之前不可用(UNIX 时间戳),设置为令牌发行时间前 5 秒。
  • iat: 此令牌的发行时间(UNIX 时间戳),设置为令牌发行时间。
  • jti: JWT ID,设置为随机创建的 UUID(例如:0099dd6c-b66e-4787-8ae2-c451d86025ae)。
  • gitlab_realm: 用于区分来自 GitLab Self-Managed 和 GitLab.com 的请求的字符串。当由 Customers Portal 发行时为 self-managed,当由 GitLab.com 发行时为 saas
  • scopes: 访问范围列表,定义此令牌有效的功能。我们根据如何将付费功能捆绑到 GitLab 版本和插件中的决定来获取这些。

用于用户访问的 JWT 包含以下声明(非详尽,可能变更):

  • aud: 受众。这是后端服务的名称(gitlab-ai-gateway)。
  • sub: 主题。这是发行令牌的 GitLab 用户的全局唯一匿名用户 ID 哈希(例如:W2HPShrOch8RMah8ZWsjrXtAXo+stqKsNX0exQ1rsQQ=)。
  • iss: 发行者(gitlab-ai-gateway)。
  • exp: 令牌的过期时间(UNIX 时间戳)。目前为发行时间后 1 小时。
  • nbf: 此令牌在此时间之前不可用(UNIX 时间戳),设置为令牌发行时间。
  • iat: 此令牌的发行时间(UNIX 时间戳),设置为令牌发行时间。
  • jti: JWT ID,设置为随机创建的 UUID(例如:0099dd6c-b66e-4787-8ae2-c451d86025ae)。
  • gitlab_realm: 用于区分来自 GitLab Self-Managed 和 GitLab.com 的请求的字符串。可以是 self-managedsaas
  • scopes: 访问范围列表,定义此令牌有效的功能。我们根据如何将付费功能捆绑到 GitLab 版本和插件中以及哪些功能允许使用用户令牌访问来获取这些。

JWKS 包含令牌验证器用于验证令牌签名的公钥。目前所有后端服务都需要:

  • 定期从 GitLab.com 和 CustomersDot 刷新 JWKS,以便密钥轮换可以轻松、定期地进行而不会中断服务。
  • 对每个 JWT 执行签名验证和访问范围检查。

以下流程图应该有助于理解当用户使用 Cloud Connector 功能(例如与 AI 聊天机器人对话)时发生的情况,适用于 GitLab.com 和 GitLab Dedicated/GitLab Self-Managed 部署。

GitLab.com

由于 GitLab.com 部署享有特殊信任,它能够为每个 Cloud Connector 功能请求自签名和创建 IJWT,这大大简化了流程:

sequenceDiagram
    autonumber
    participant U as User
    participant GL as GitLab.com
    participant SB as Backend service

    Note over U,SB: End-user flow
    U->>GL: Authorize with GitLab instance
    GL-->>U: PAT or Cookie
    U->>GL: Use Cloud Connector feature
    GL->>GL: Perform authN/authZ with Cookie or PAT
    GL->>GL: Verify user allowed to use feature
    GL->>GL: Create signed IJWT
    GL->>SB: Request feature with IJWT
    SB->>GL: Fetch public signing keys, if needed
    GL-->>SB: JWKS
    SB->>SB: Validate IJWT with keys
    SB-->>GL: Feature payload

GitLab Dedicated/Self-Managed

对于 Dedicated 和 GitLab Self-Managed 实例,主要问题是信任委托:我们不能信任任何单个 GitLab Self-Managed 实例并让它们发行令牌,但我们可以通过让实例定期向 CustomersDot 授权来委托信任,CustomersDot 由 GitLab Inc. 控制。虽然我们确实控制 GitLab Dedicated 实例,但为简单起见,我们从 Cloud Connector 的角度将它们视为"self-managed"。

与 GitLab.com 的主要区别是添加了 CustomersDot 参与者,客户实例定期与之同步以获取和持久化访问 GitLab 后端服务所需的数据。

sequenceDiagram
    autonumber
    participant U as User
    participant GL as SM/Dedicated GitLab
    participant CD as CustomersDot
    participant SB as Backend service

    Note over GL,CD: Background: synchronize access data
    loop cron job
        GL->>CD: Send license key
        CD->>CD: Verify customer subscription with license key
        CD->>CD: Create and sign IJWT
        CD-->>GL: Cloud Connector access data + IJWT
        GL->>GL: Store access data + IJWT in DB
    end
    Note over U,SB: End-user flow
    U->>GL: Authorize with GitLab instance
    GL-->>U: PAT or Cookie
    U->>GL: Use Cloud Connector feature
    GL->>GL: Perform authN/authZ with Cookie or PAT
    GL->>GL: Verify user allowed to use feature
    GL->>GL: Load IJWT from DB
    GL->>SB: Request feature with IJWT
    SB->>CD: Fetch public signing keys, if needed
    CD-->>SB: JWKS
    SB->>SB: Validate IJWT with keys
    SB-->>GL: Feature payload

Cloud Connector 访问数据是存储在实例本地数据库中的结构化 JSON 数据。除了 IJWT 外,它还包含有关可用服务的附加信息,例如服务是否被视为完全发布或处于测试阶段。这些信息对于我们不控制升级节奏的 GitLab Self-Managed 实例特别有用,因为它允许我们同步可能发生变化的数据并远程控制对某些 GitLab 功能的访问。

AI 网关

AI 网关能够发行 UJWT,这些 UJWT 用于用户直接与 AI 网关通信,即无需先调用 GitLab 实例。除了使用 IJWT 外,还可以这样做。只有 GitLab 实例可以请求 UJWT,这是通过使用 IJWT 发出请求来完成的。AI 网关将返回一个短期 UJWT,实例可以将其传递给用户。客户端可以使用此 UJWT 直接与 AI 网关通信。

sequenceDiagram
    autonumber
    participant U as User
    participant GL as SM/Dedicated GitLab or GitLab.com
    participant AIGW as AI gateway

    U->>GL: Authorize with GitLab instance
    GL-->>U: PAT or Cookie

    loop Initial request, this will be done hourly, only when the UJWT is expired.
        U->>GL: Request UJWT
        GL->>GL: Perform authN/authZ with Cookie or PAT
        GL->>GL: Verify user allowed to use feature
        Note over GL: Step 6 differs between SM/Dedicated GitLab and GitLab.com
        GL->>GL: SM/Dedicated GitLab: Load IJWT from DB<br/>GitLab.com: Create signed IJWT
        GL->>AIGW: Request UJWT with IJWT
        AIGW->>AIGW: Validate IJWT with keys
        AIGW->>AIGW: Create UJWT
        AIGW-->>GL: UJWT
        GL-->>U: UJWT
    end
    U->>AIGW: Request feature with UJWT
    AIGW->>U: Feature payload

参考资料