
Activepieces Secret Managers 深度指南接入 Vault / AWS / Conjur / 1Password 实现运行时密钥解析【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces导读本文以 Activepieces 开源仓库中的 Secret Managers 功能为核心完整讲解平台管理员如何将 HashiCorp Vault、AWS Secrets Manager、CyberArk Conjur、1Password 接入 Activepieces使 Flow 步骤与连接Connection中的敏感值在运行时从外部密钥存储解析而非落库存储。读完本文你将掌握 secret_manager_connection 实体结构、四种 Provider 的配置字段、{{connectionId|path}}引用语法、Redis 缓存机制、/v1/secret-managersREST API 及常见坑位并了解引擎侧resolveString/resolveObject的解析链路与源码级实现依据。一、Secret Managers 是什么为什么要把密钥从数据库搬到外部密钥库在默认架构下Activepieces 的 Flow 步骤参数与 App Connection 中涉及的敏感值API Key、Token、密码等经过加密后存储在应用数据库中。当平台合规要求如等保、SOC 2、企业安全策略规定“密钥必须托管在专用密钥管理系统”时就需要一种机制把敏感值的存取委托给外部 Secret Store。Activepieces 的 Secret Managers 功能正是为此设计平台管理员可以创建一条secret_manager_connection记录指向外部密钥存储HashiCorp Vault、AWS Secrets Manager、CyberArk Conjur、1Password随后在 Flow 步骤或连接的敏感字段中使用{{connectionIdseparatorpath}}形式的引用引擎在运行时通过对应 Provider 从外部密钥库取回真实值而不是把密钥明文写入数据库。该功能受平台级开关platform.plan.secretManagersEnabled门控属于 EE/Cloud 版本能力。在服务端入口 secret-managers.module.ts 中可以看到门控实现app.addHook(preHandler, platformMustHaveFeatureEnabled((platform) platform.plan.secretManagersEnabled)) await app.register(secretManagersController, { prefix: /v1/secret-managers })并且该模块在 app.ts 与 app.ts 中分别注册EE 版与 Cloud 版各一次。二、核心数据模型secret_manager_connection 实体每个外部密钥存储连接对应数据库表secret_manager_connection中的一行记录其 TypeORM 实体定义在 secret-manager.entity.ts字段类型说明idApId主键即引用语法中的connectionIdplatformIdFK → platform平台外键onDelete: CASCADE删除平台级联删除该行providerIdString供应商标识hashicorp/aws/cyberark-conjur/onepasswordnameString连接名称界面展示用scopeString可见范围PLATFORM默认或PROJECTprojectIdsjsonb当 scope 为PROJECT时允许访问的项目 ID 数组authjsonb加密后的 Provider 配置EncryptedObject几个值得注意的设计点平台外键级联删除实体通过relations.platform声明many-to-one关系与onDelete: CASCADE数据库层面保证平台被删除时连接记录随之清除。范围过滤使用 PostgreSQL包含运算符在服务端 secret-managers.service.ts 的list与getSecret中PROJECT 作用域查询条件为sm.projectIds :projectIds::jsonb即“当前项目是否被包含在连接的 projectIds 数组中”这是对 jsonb 数组包含关系的标准查询写法。凭据加密存储auth字段保存的是经encryptUtils.encryptObject加密的 Provider 配置对象读取时用encryptUtils.decryptObject解密后再调用 Provider明文凭据不会以可读形式落入数据库。三、支持的 Provider 与配置字段Provider 类型定义在共享包 dto.ts枚举SecretManagerProviderId四种 Provider 的配置 Schema 全部基于 zod 定义必填字段均有min(1)校验formErrors.required1. HashiCorp Vaulthashicorp{ url: string, // Vault 地址必填 namespace?: string, // Vault Enterprise Namespace可选 roleId: string, // AppRole Role ID必填 secretId: string, // AppRole Secret ID必填 }实现位于 hashicorp-provider.ts。认证方式为AppRole先向/v1/auth/approle/login提交role_id/secret_id换取client_token随后所有请求携带X-Vault-Token头若配置了 namespace 还会附带X-Vault-Namespace。checkConnection在登录成功后还会请求/v1/sys/mounts验证 AppRole 策略具备必要权限。路径格式约束Vault 路径必须形如mount/data/path/key且至少包含 3 段validatePathFormat强制校验。解析时去掉末尾斜杠后取最后一段作为密钥 Key其余部分作为读取的 mount 路径// 参考hashicorp-provider.ts 中 getSecret 的路径拆分 const pathParts request.path.split(/) const mountPath pathParts.slice(0, -1).join(/) // 请求 /v1/{mountPath} const secretKey pathParts.slice(-1)[0] // 从响应 data.data 中取该 key2. AWS Secrets Manageraws{ accessKeyId: string, // AWS Access Key ID必填 secretAccessKey: string, // AWS Secret Access Key必填 region: string, // 区域必填 }实现位于 aws-provider.ts直接使用aws-sdk/client-secrets-manager。checkConnection通过ListSecretsCommand({ MaxResults: 1 })验证凭据与区域可达性。路径格式约束AWS 的路径采用secretName:secretJsonKey冒号分隔格式例如prod/db-credentials:password。读取流程为GetSecretValueCommand({ SecretId: secretName })取回SecretStringJSON.parse后取secretJsonKey对应的字符串值。注意二进制类型的 Secret 不受支持取回空值或二进制值时直接抛错。3. CyberArk Conjurcyberark-conjur{ organizationAccountName: string, // 组织账户名必填 loginId: string, // 登录 ID必填 url: string, // Conjur 地址必填 apiKey: string, // API Key必填 }配置 Schema 同样定义于 dto.ts对应实现文件为 cyberark-conjur-provider.ts。4. 1Passwordonepassword{ serviceAccountToken: string, // 1Password Service Account Token必填 }实现位于 onepassword-provider.ts基于官方1password/sdk创建客户端createClient({ auth: config.serviceAccountToken, integrationName: Activepieces, integrationVersion: v1.0.0, })checkConnection通过client.vaults.list()验证 Token 有效读取使用client.secrets.resolve(path)路径必须符合 1Password 引用格式op://vault/item/field正则^op:\/\/[^/]\/[^/]\/.$强校验。Provider 分发与统一接口所有 Provider 遵循同一接口契约定义于 secret-manager-providers.tstype SecretManagerProviderK { checkConnection: (config) Promiseunknown // 探测连通性 connect: (config) Promisevoid // 建连内部调用 checkConnection disconnect: () Promisevoid // 断开当前实现为空操作 getSecret: ({ path }, config) Promisestring // 按路径取密钥 }工厂函数secretManagerProvider(log, providerId)根据providerId从secretManagerProvidersMap中分发到对应实现统一包装的throwConnectionError/throwGetSecretError会将错误归类为SECRET_MANAGER_CONNECTION_FAILED/SECRET_MANAGER_GET_SECRET_FAILED并记录日志。四、运行时密钥解析引用语法与解析链路4.1 引用语法敏感字段的引用格式为{{connectionIdseparatorpath}}其中separator是共享包 index.ts 中定义的常量SecretManagerFieldsSeparatorexport const SecretManagerFieldsSeparator |ap_sep_v1|即引用形如{{connectionId|ap_sep_v1|path}}。使用较长且唯一的内部常量作为分隔符是为了避免路径本身包含|等常见字符时产生歧义。4.2 解析方法族解析逻辑全部实现在 secret-managers.service.tsresolveString对单个字符串键解析。内部先调用extractConnectionIdAndPath做三段校验——必须以{{开头且以}}结尾、必须包含分隔符、connectionId与path均非空任一不满足都会抛出SECRET_MANAGER_KEY_NOT_SECRET见下方 Gotcha。通过校验后调用getSecret真正向密钥库取值。resolveObject递归解析对象对每个字段值调用resolveUnknownValue最后用Object.fromEntries重组为同构对象。resolveUnknownValue分发器——对象走resolveObject字符串走resolveString其他类型数字、布尔、null 等原样返回。containsSecretManagerReference导出的判断辅助函数检查字符串是否“以{{开头、包含分隔符、以}}结尾”对象则递归检查任意字段供上层提前判断某个值是否包含密钥引用。getSecret是取值的核心路径顺序如下按id platformId scope/projectIds查询连接记录校验调用方项目是否有权访问该连接无权则抛SECRET_MANAGER_GET_SECRET_FAILED解密auth得到 Provider 配置配置缺失同样抛错先查 Redis 缓存(platformId, connectionId, path)命中直接返回未命中则调用provider.getSecret({ path }, config)从外部密钥库取回明文写入缓存后返回。4.3 失败语义throwOnFailureresolveString/resolveObject/resolveUnknownValue均接受throwOnFailure参数throwOnFailure true默认解析失败抛错让 Flow 运行失败throwOnFailure false失败时返回原始值即原样保留{{...}}引用文本特例当错误码为SECRET_MANAGER_KEY_NOT_SECRET值不是合法引用时无论开关如何都返回原值——这与 4.1 的 Gotcha 语义一致。五、Redis 缓存命中、TTL 与失效缓存实现位于 secret-manager-cache.ts底层使用distributedStoreRedis密钥值缓存key 形如secret-manager:secret:{platformId}:{connectionId}:{path}value 为加密后的密钥字符串写入时encryptString读取时decryptStringTTL 为 1 小时apDayjsDuration(1, hour).asSeconds()。连接状态缓存key 形如secret-manager:check:{platformId}:{connectionId}value 为布尔值同样 1 小时 TTL用于加速列表页与解析前的连通性判断且仅在探测成功时写入。失效策略创建 / 更新 / 删除连接或调用DELETE /cache端点时通过invalidateConnectionEntries用 Redis SCAN 匹配模式删除缓存。指定connectionId时匹配secret-manager:*:{platformId}:{connectionId}*否则匹配整个平台的secret-manager:*:{platformId}:*。缓存的意义在于外部密钥库通常有速率限制与网络延迟1 小时 TTL 在“及时拿到密钥轮换结果”与“降低外部依赖压力”之间取了折中而失效端点则提供了运维侧主动清缓存的逃生通道例如刚轮换了 Vault 中的密钥希望立即生效。六、REST API/v1/secret-managers 端点详解控制器定义于 secret-managers.controller.ts所有端点位于/v1/secret-managers方法路径权限说明GET/publicPlatform([USER])列表跨平台列出需要平台管理员按项目查询需READ_APP_CONNECTION权限POST/platformAdminOnly([USER])创建连接先provider.connect验证连通性再保存返回 201POST/:idplatformAdminOnly([USER])更新连接同样先验证连通性再落库DELETE/:idplatformAdminOnly([USER])删除连接返回 204DELETE/cacheplatformAdminOnly([USER, SERVICE])按connectionId可选 query 参数清除缓存返回 204请求体由ConnectSecretManagerRequestSchemazod discriminatedUnion校验providerId决定config的 Schema当scope PROJECT时superRefine强制projectIds至少包含一个项目否则校验失败并提示 “Please select at least one project”。GET /的列表权限值得注意平台管理员PlatformRole.ADMIN可以直接列出全平台连接非管理员必须携带projectIdquery 参数并经rbacService.assertPrinicpalAccessToProject校验READ_APP_CONNECTION权限。返回结构中auth字段被剔除仅暴露configured/connected两个状态布尔值避免敏感信息外泄。七、Gotchas实现细节中的关键坑位7.1 不是所有{{...}}都是密钥引用一个值若不以{{开头或不包含分隔符会被当作普通字面量原样返回错误码为SECRET_MANAGER_KEY_NOT_SECRET不是错误。这在extractConnectionIdAndPath的三段校验中体现trim 后不满足{{...}}包裹、找不到分隔符、或 connectionId/path 为空都抛该错误码而handleResolveError会将其还原为原始值返回。因此用户字段中偶然出现的{{something}}不会被误判为密钥解析失败。7.2 创建/更新前必须验证连通性create与update在保存到数据库之前都会调用provider.connect(config)内部即checkConnection验证失败则直接抛SECRET_MANAGER_CONNECTION_FAILED不会落库。这保证了数据库中不会存在“配置了但连不上”的脏数据。7.3 作用域是硬约束不是软提示getSecret在取值前会用scope PLATFORM或scope PROJECT AND projectIds 当前项目的组合条件查询连接查不到即拒绝解析。也就是说一个 PROJECT 作用域连接即使被其他项目引用解析也会失败作用域在服务端是权威执行而非仅界面提示。7.4 各 Provider 路径格式差异巨大同样是path字段四种 Provider 的语义完全不同HashiCorpmount/data/path/key至少 3 段最后一段是 keyAWSsecretName:secretJsonKey冒号分隔1Passwordop://vault/item/field正则强校验CyberArk Conjur遵循 Conjur 自身的变量路径约定。配置引用时务必按目标 Provider 的格式书写path否则会得到VALIDATION校验错误。八、前端与管理面平台安全设置页功能的前端入口位于 web/src/app/routes/platform/security/secret-managers平台管理员的“安全设置”页面与连接配置对话框前端 API 封装与 hooks 位于 web/src/features/secret-managers。平台管理员在 UI 上选择 Provider、填写对应配置、选择PLATFORM或PROJECT作用域后者需勾选项目保存后即可在 Flow 的敏感字段中使用{{connectionId|ap_sep_v1|path}}引用。九、测试与验证集成测试与 Mock功能配套的集成测试位于 packages/server/api/test/integration/ee/secret-managers其中包含一个 HashiCorp Vault 的 mock 服务用于在无真实 Vault 环境下验证连通性检查、密钥解析、缓存命中/失效等完整链路。如果你是自建平台并希望验证 Secret Managers 行为可参考该测试目录中的 mock 构造方式与断言逻辑。十、落地建议与注意事项确认版本门控Secret Managers 依赖platform.plan.secretManagersEnabled仅 EE/Cloud 版本开放自建 CE 部署无法启用模块在 app.ts 与 app.ts 注册于 EE/Cloud 分支。最小权限原则Vault 的 AppRole 策略、AWS IAM 凭据、Conjur 主机权限、1Password Service Account 均应按“仅能读取所需路径”的最小权限配置——checkConnection中 Vault 会实际请求/v1/sys/mounts权限不足会直接导致连接失败。缓存与轮换密钥值在 Redis 缓存 1 小时密钥轮换后如需立即生效调用DELETE /v1/secret-managers/cache清理对应连接的缓存。敏感值不落库auth配置字段与缓存中的密钥值均为加密存储Flow 运行时通过引用解析避免把明文密钥写入流程定义与数据库。正确书写引用与路径统一使用{{connectionId|ap_sep_v1|path}}并根据 Provider 规范书写 path 段格式。关键文件索引模块入口与门控secret-managers.module.ts服务层解析与 CRUDsecret-managers.service.tsREST 控制器 secret-managers.controller.tsTypeORM 实体 secret-manager.entity.tsRedis 缓存 secret-manager-cache.tsProvider 实现目录 secret-manager-providers共享 DTO 与 Schema dto.ts、index.ts前端 API 与 hooks web/src/features/secret-managers平台管理 UI web/src/app/routes/platform/security/secret-managers集成测试含 Vault mock packages/server/api/test/integration/ee/secret-managers主要消费方App Connection 解析 packages/server/api/src/app/app-connection【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考