Infisical 重构 Kubernetes Operator,解决扩展性瓶颈

infisical 发布于 2026-06-26 阅读 109

Infisical 团队因原有 Kubernetes Operator 在规模扩展时出现内存占用高、重启认证风暴、配置变更繁琐等问题,决定重构 Operator。

发布于 2026 年 6 月 24 日,星期三

博客图片

安全性与便利性常常相互矛盾,但人类大脑更偏爱便利性(并且即使出于好意也会犯错)。大多数身份安全工具通过尽可能让安全性变得便利来调和这一矛盾。

任何摩擦都会增加人们构建便捷的变通方法或绕过安全工具的风险,从而削弱组织的安全态势。

这就是为什么我们在意识到我们的 Kubernetes operator在规模化时表现不佳后,对其进行了重新架构,以提升性能和开发者体验。

为什么我们要构建一个 Kubernetes operator

优秀机密管理的原则之一是中心化。将所有机密统一起来,可以提供一个集中存储、管理和审计基础设施中所有机密的地方。

中心化需要将机密同步到每种类型的基础设施和部署模型中。这意味着将机密从机密存储交付到用户的基础设施,再到使用该机密的服务。理想情况下,这不需要变通方法或自定义逻辑,以免造成安全漏洞或给用户增加维护负担。

我们的第一个 Kubernetes operator 将原生机密同步扩展到分布式部署中。它虽然能用,但扩展性不佳。随着集群或部署中的资源数量激增,其内存占用急剧膨胀,性能也随之下降。

这就是为什么我们采用了一种基于引用的新架构重新设计了 operator。

我们第一个 Kubernetes operator 的问题所在

要将机密大规模同步到 Kubernetes,我们的 operator 需要做几件事:

  • 连接并认证到 Infisical: API 托管在哪里,如何连接并认证到它。
  • 在 Infisical 中找到正确的机密: 知道 Infisical 中正确的机密路径:哪个项目、环境、文件夹等。
  • 让 Pod 和 Deployment 能够使用它们: 将机密调和成 Kubernetes 原生的 secret 对象,以便 Deployment 和 Pod 能够将机密放入正确的环境。

我们最初的设计满足了这些要求,但随着工作负载的增加,问题开始暴露。

为什么 v1 的架构在规模上遇到困难

在 v1 中,用户编写了指向 Infisical 机密的单体式自定义 InfisicalSecret 资源。v1alpha1 API 上的每个 InfisicalSecret 资源包含:

  • Infisical 实例的地址
  • 认证凭据
  • 拉取机密的范围
  • 要写入的受管理 Kubernetes secret

一个资源看起来像这样:

apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: service-a-secrets
spec:
  hostAPI: https://app.infisical.com/api
  authentication:
    universalAuth:
      credentialsRef:
        secretName: universal-auth-credentials
        secretNamespace: default
      secretsScope:
        projectSlug: my-project
        envSlug: prod
        secretsPath: "/service-a"
  managedSecretReference:
    secretName: service-a-managed
    secretNamespace: default

可扩展性受到影响,因为每个资源都复制了认证和连接。这种架构在持久基础设施上可以工作。一台 VPS 或虚拟机是一个身份,只在重启或配置更改时重新认证。然而,Kubernetes 集群包含数十或数百个这样的资源,并且会频繁重新部署和重启。由于每个资源都携带自己的认证和连接,每个资源都持有自己的独立客户端。这产生了三个问题:

  • 资源消耗了过大的内存,因为每个资源在内存中持有自己的客户端。在规模较大时,会导致内存不足问题,需要提高 Helm 内存限制。每次 Pod 发生 OOM 时,每个资源都会同时进行调和和认证。
  • 重启会产生大量同时发生的认证调用,从而遇到速率限制。经过退避和重试后,operator 最终会成功,但这会导致集群达到稳定状态的延迟增加。
  • 工程团队需要做额外的工作。轮换机器身份或更改 Infisical 主机意味着要编辑每个资源上的认证块。

根本问题是过载的 CRD 架构,而不是缺少逻辑。我们评估了事件处理器、抖动和其他逻辑。这些可能有所帮助,但会给已经过载的 CRD 增加更多复杂性。

我们只能通过新的架构来解决根本问题。

基于引用的架构如何解决了复制问题

新设计将连接、认证和同步分离开来。机密引用认证和连接资源作为共享对象。这解决了性能问题并改善了开发者体验。

我们大致参照了 External Secrets Operator(ESO)的资源拆分方式来建模新架构,ESO 将 providerstoreexternalsecret CRD 分开。Infisical 与 ESO 集成,但我们构建自己的 operator 有两个原因:

  • ESO 曾一度暂停开发。虽然现在已经恢复,但创建一个可能停止开发的依赖并不理想。
  • 我们希望提供原生体验,最小化组件数量,并最终支持动态机密推送机密(起源于 Kubernetes 并最终进入 Infisical 的机密),而 ESO 不支持这些。

Infisical Kubernetes Operator 的 v2 版本 v1beta1 引入了三个 CRD:

  • InfisicalConnection 定义了 Infisical 实例的地址和可选的 TLS 设置。
  • InfisicalAuth 定义了机器身份的认证细节,并引用一个连接。
  • InfisicalStaticSecret 定义了一个同步并引用一个认证资源。它取代了 InfisicalSecret

注意:我们仍在开发 InfisicalDynamicSecretInfisicalPushSecret 的 CRD。

InfisicalConnectionInfisicalAuth 只需定义一次,而机密资源则指向它们。这确保了 InfisicalStaticSecret 无需运行自己的客户端即可找到、拉取并调和机密。

以下是一个连接资源的示例:

apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
  name: my-infisical-connection
spec:
  address: https://app.infisical.com

以下是如何定义认证:

apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
  name: prod-auth
spec:
  infisicalConnectionRef:
    name: my-infisical-connection
    namespace: default
  method: universal
  universal:
    clientIdRef:
      name: universal-auth-credentials
      namespace: default
      key: clientId
    clientSecretRef:
      name: universal-auth-credentials
      namespace: default
      key: clientSecret

最终的 InfisicalStaticSecret 资源如下所示:

apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
  name: service-a-secrets
spec:
  infisicalAuthRef:
    name: prod-auth
    namespace: default
  sources:
    - projectId: <your-project-id>
      environmentSlug: prod
      secretPath: /service-a
  targets:
    - name: service-a-managed
      namespace: default
      kind: Secret
      creationPolicy: Owner

InfisicalAuth 现在是配置的一部分。控制器会解析每个 InfisicalStaticSecret 的认证引用,以获取按身份缓存的客户端。这为每个身份创建了一个客户端,而不是为每个资源创建一个客户端。任何指向同一身份的 InfisicalStaticSecret 都会重用认证和连接。

这解决了之前的问题:

  • 重启每个身份只产生一次认证调用,而不是每个资源一次。
  • 更改 Infisical 主机或机器身份只需编辑一个资源。
  • 客户端不会在每个资源上复制,从而减少了内存占用。

缓存是懒加载的,但会在配置更改或调用返回 401 或 403 时失效。然后 operator 会丢弃缓存的客户端并重新认证。

为了解决内存、认证和连接问题,我们本可以在内部按身份对客户端进行去重。但我们选择将单体 CRD 拆分为三个,以改善开发者体验。我们的 operator 现在沿用了 ESO 中广为人知的模式,并且避免了在配置更改时批量编辑 CRD。

除了重新架构的 CRD,我们在 v2 中还进行了三个较小的升级:

  • InfisicalStaticSecret 可以从多个源路径拉取机密。这允许工作负载从不同路径消费机密。如果平台团队在 /shared/auth 拥有认证凭据,而应用团队在 /app/integrations 拥有集成密钥,CRD 原生支持这一点。
  • 它可以写入多个目标,目标可以是 Kubernetes secretConfigMap。这允许将敏感值拉取到 Secret 中,将非敏感值拉取到 ConfigMap 中。这对于将值获取到仅接受 ConfigMap 挂载的 sidecar 也很有用。
  • 现在每个资源都会报告就绪状态,因此 kubectl get 可以显示每个资源的健康状况。

升级到 Infisical Kubernetes Operator v2

我们目前同时维护 v1alpha1v1beta1,但计划最终弃用 v1alpha1 API。我们的文档包含一个迁移指南,以及更通用的安装和使用 Kubernetes operator 的详细说明。

为什么 Kubernetes 对我们很重要

软件类别决定了工程优先级。产品经理和工程师在问题跟踪器上花费大量时间,因此 Linear 在低延迟、清晰的 UI 以及键盘快捷键和 cmd+k 导航等 UX 功能上投入了大量精力。

在安全类别中,产品需要能够在任何基础设施、部署模型和工作负载规模上工作。缺口或并行系统会带来摩擦,而自动化和中心化本应防止这种摩擦。任何变通方法、重复的机密管理器,或者“就这一次,我们在这里使用明文”都是潜在的安全漏洞。

在理想情况下,Infisical 应该能够为一个同时在所有三大云提供商、一台专用 VPS 以及它们自 1990 年代以来一直维护的服务器地下室中使用我们的公司保护机密。

Kubernetes 在各个规模的组织中变得越来越流行,因此在 Infisical 上管理 Kubernetes 机密需要无缝衔接。这使得像 Kubernetes operator 的可扩展性这样看似微小的事情变得重要。

Finn 头像 Finn , Infisical 技术内容营销人员

  • 原文链接: infisical.com/blog/kuber...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论