拦截器

拦截器是 Tekton Triggers 中一个强大的组件,用于在事件数据到达 TriggerBindings 和 TriggerTemplates 之前对其进行处理和过滤。它充当了传入 webhook 事件的守门人和转换器,使您能够验证、过滤和修改事件数据,以确保只有相关事件能够触发您的流水线。

术语解释

术语描述
拦截器在 webhook 事件到达 TriggerBindings 和 TriggerTemplates 之前处理的组件。
集群拦截器一种集群范围的拦截器,可以在所有命名空间中使用。
CEL通用表达语言,用于过滤和转换事件数据。
扩展拦截器添加的额外数据字段,TriggerBindings 可以访问这些字段。
Webhook当外部系统中发生特定事件时,交付事件数据的 HTTP 回调。

为什么我们需要拦截器

事件处理的挑战

在响应外部事件的 CI/CD 系统中,会面临若干挑战:

  1. 事件验证:需要对外部 webhook 进行验证,以确保它们来自受信任的来源。
  2. 事件过滤:并不是所有事件都应触发流水线;您需要根据事件类型或内容进行过滤。
  3. 数据转换:原始的 webhook 负载通常包含比所需更多的数据或需要重构。
  4. 安全问题:如果没有适当的验证,webhook 端点可能会面临滥用的风险。

在没有拦截器的情况下,解决这些挑战将需要:

  • 针对每个 webhook 来源的自定义验证代码
  • 在流水线定义中嵌入复杂逻辑
  • 在脚本中进行手动过滤和转换
  • 针对每个集成的单独安全机制

拦截器如何解决这些问题

拦截器提供了一种标准化的声明性方式来:

  1. 验证事件:验证 webhook 签名和令牌以确保其真实性。
  2. 过滤事件:基于类型、内容或其他标准仅处理相关事件。
  3. 转换数据:提取、修改或添加数据,以使其更适合流水线消费。
  4. 增强安全性:在所有 webhook 集成中实施一致的安全实践。
  5. 模块化逻辑:将事件处理关注点与流水线执行分离。

这种方法在事件接收、处理和流水线执行之间创建了清晰的分离,使您的 CI/CD 系统更易于维护和更安全。

优势

  • 增强安全性:在处理之前验证 webhook 的真实性
  • 减少流水线复杂性:将过滤和转换逻辑移出流水线
  • 标准化处理:跨不同来源一致处理事件
  • 灵活性:为复杂处理需求链式连接多个拦截器
  • 可扩展性:为专业处理需求创建自定义拦截器
  • 可重用性:仅需定义拦截器一次即可在多个触发器中重用
  • 声明性配置:使用 Kubernetes 资源配置事件处理

适用场景

拦截器在以下场景中至关重要:

  1. 安全的 Webhook 处理:当您需要验证 webhook 事件是否来自受信任的来源。

  2. 条件流水线执行:当您希望仅针对特定事件类型或内容(例如,只有在主分支上进行推送事件时)触发流水线。

  3. 数据丰富:当您需要从复杂事件负载中添加计算值或提取特定数据。

  4. 多来源集成:当与多个 webhook 提供商(GitHub、GitLab、Bitbucket)集成时,保持一致的处理。

  5. 自定义事件处理:当实现超出标准拦截器可用功能的专业逻辑时。

限制与局限性

  • 拦截器为事件处理增加了处理开销
  • 复杂的 CEL 表达式可能难以调试
  • 自定义拦截器需要额外的部署和管理
  • 建议使用 HTTPS 以确保安全,并将在未来版本中移除对 HTTP 的支持
  • 拦截器必须获得适当的保护,以防止未经授权的访问

原则

拦截器架构

拦截器位于 EventListener 和触发处理流水线之间:

  1. EventListener 接收 webhook 事件
  2. 拦截器 处理和过滤事件
  3. TriggerBindings 从处理后的事件中提取数据
  4. TriggerTemplates 使用提取的数据创建资源

拦截器可以链式连接,每个拦截器接收来自前一个拦截器的输出。这允许创建复杂的处理流水线,每个拦截器执行特定功能。

拦截器类型

Tekton Triggers 支持两种拦截器的实现:

  1. 独立拦截器:作为单独的 Kubernetes 服务实现

    • 拦截器:命名空间范围的自定义资源
    • 集群拦截器:集群范围的自定义资源
    • 更灵活,且更易于扩展
    • 可以使用任何可以提供 HTTP 请求的语言实现
  2. 内置拦截器:包含在 EventListener pod 中

    • GitHub、GitLab、Bitbucket、CEL 等
    • 为了向后兼容而保留
    • 更易于使用,但扩展性较差

拦截器结构

基本的拦截器资源具有以下结构:

apiVersion: triggers.tekton.dev/v1alpha1
kind: Interceptor
metadata:
  name: my-interceptor
spec:
  clientConfig:
    service:
      name: my-interceptor-svc
      namespace: default
      path: "/optional-path"  # 可选
      port: 8081  # 默认为 80

在触发器中引用时:

triggers:
  - name: trigger-with-interceptor
    interceptors:
      - ref:
          name: "my-interceptor"
          kind: Interceptor  # 或 ClusterInterceptor
          namespace: default  # 仅对 Interceptor 必需
        params:  # 可选参数
          - name: "param1"
            value: "value1"

配置示例

GitHub 拦截器示例

triggers:
  - name: github-push-trigger
    interceptors:
      - ref:
          name: "github"
        params:
          - name: "secretRef"
            value:
              secretName: github-secret
              secretKey: secretToken
          - name: "eventTypes"
            value: ["push"]
          - name: "branches"
            value: ["main", "release/*"]

带 CEL 的 GitLab 拦截器示例

triggers:
  - name: gitlab-merge-request-trigger
    interceptors:
      - ref:
          name: "gitlab"
        params:
          - name: "secretRef"
            value:
              secretName: gitlab-secret
              secretKey: secretToken
          - name: "eventTypes"
            value: ["Merge Request Hook"]
      - ref:
          name: "cel"
        params:
          - name: "filter"
            value: "body.object_attributes.state == 'opened' || body.object_attributes.state == 'reopened'"
          - name: "overlays"
            value:
              - key: truncated_sha
                expression: "body.object_attributes.last_commit.id.truncate(7)"

自定义拦截器示例

  1. 创建您自定义拦截器的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: custom-interceptor
spec:
  replicas: 1
  selector:
    matchLabels:
      app: custom-interceptor
  template:
    metadata:
      labels:
        app: custom-interceptor
    spec:
      containers:
        - name: custom-interceptor
          image: custom-interceptor:latest
          ports:
            - containerPort: 8080
  1. 创建您自定义拦截器的 Service:
apiVersion: v1
kind: Service
metadata:
  name: custom-interceptor-svc
spec:
  selector:
    app: custom-interceptor
  ports:
    - port: 80
      targetPort: 8080
  1. 注册您的自定义拦截器:
apiVersion: triggers.tekton.dev/v1alpha1
kind: ClusterInterceptor
metadata:
  name: custom-interceptor
spec:
  clientConfig:
    service:
      name: custom-interceptor-svc
      namespace: default
      port: 80

与拦截器相关的重要参数说明

CEL 表达式

CEL(通用表达语言)是用于过滤和转换事件数据的 CEL 拦截器的强大工具。

适用场景

  • 基于复杂条件过滤事件
  • 从事件负载中提取特定数据
  • 根据现有数据创建新字段
  • 实现条件逻辑

限制与局限性

  • 复杂的表达式可能难以调试
  • 仅限于 CEL 提供的功能
  • 非常复杂的表达式可能对性能产生影响

原则/参数说明

常见的 CEL 模式:

  • 访问主体字段:body.repository.full_name
  • 访问头字段:header.X-GitHub-Event
  • 字符串操作:body.ref.split('/')[2]
  • 条件判断:body.action in ['opened', 'reopened', 'synchronize']
  • 布尔逻辑:body.pull_request.base.ref == 'main' && body.action == 'opened'

配置示例

- ref:
    name: "cel"
  params:
    - name: "filter"
      value: "header.match('X-GitHub-Event', 'pull_request') && body.action in ['opened', 'reopened', 'synchronize']"
    - name: "overlays"
      value:
        - key: branch_name
          expression: "body.pull_request.head.ref"
        - key: is_main_target
          expression: "body.pull_request.base.ref == 'main'"

HTTPS 配置

建议在 HTTPS 上运行拦截器以确保安全,并将在未来版本中强制要求。

适用场景

  • 生产环境
  • 处理敏感数据
  • 符合安全要求

限制与局限性

  • 需要适当的证书管理
  • 与 HTTP 相比需要额外配置

原则/参数说明

要为拦截器配置 HTTPS:

  1. 为您的拦截器添加 server/type: https 标签
  2. 提供证书验证的 CA 包
  3. 确保您的拦截器服务配置为提供 HTTPS

配置示例

apiVersion: triggers.tekton.dev/v1alpha1
kind: Interceptor
metadata:
  name: secure-interceptor
  labels:
    server/type: https
spec:
  clientConfig:
    caBundle: "BASE64_ENCODED_CA_BUNDLE"
    service:
      name: secure-interceptor-svc
      namespace: default
      port: 8443

参考材料