环境配置与服务鉴权
使用环境配置、Provider 绑定和 consumer token 隔离后端部署环境。
同一个 Artifact 应能够部署到多个环境。所有环境差异都通过 Hosted Service Environment 管理,但必须区分 两类配置:应用配置由部署解析后提供给业务进程;运行治理配置由 Hosted Service、OpenResty 和运行载体消费, 不进入业务代码。完整责任划分见架构与资源边界。
Resource Binding 的通用边界、当前公开能力和申请流程见 基础能力与 Resource Binding。数据库 Profile 和 Object Storage Profile 是当前 明确支持的 Hosted Service Provider 绑定;不要因为某项基础能力在 Runtime 中可见,就假设 Hosted Service 已支持该绑定类型。
环境配置
应用配置用于改变同一 Artifact 在目标 Environment 中的业务运行参数。适合放入应用配置的内容包括:
- 日志级别、功能开关和外部服务地址
- 业务运行参数
- 数据库 Profile 或 Allocation 的绑定引用
- Object Storage Profile 的绑定引用
- 第三方凭据 Provider 的绑定引用
敏感值不要直接写入源码、Artifact 元数据、公开文档或普通日志。配置变更应形成可审计的修订,并在部署前确认解析结果。
实例数量、扩缩容策略、CPU/内存限制、通用请求限流和并发保护属于运行治理配置。它们可以在产品界面上归属
目标 Environment,但必须使用 Hosted Service 定义的类型化字段、独立校验和版本化修订,并受 Slot 当前容量
权益约束;不能把 replicaCount、rateLimit 等自定义普通配置键注入 Rust 进程后由业务代码执行。Rust 进程
不得读取或决定副本数,也不应重复实现平台已经承诺的通用流量治理。
当前是否支持某个治理项以及准确参数,以工作区当前 Runtime 方法定义和 Slot 目录为准。方法定义中尚未提供的 治理能力不能通过普通 Environment 配置绕过;平台能力正式提供并完成运行态验证前,文档也不能宣称该治理已生效。
使用前通过当前 CLI 帮助确认参数:
baijimu hosted-service env --help
baijimu hosted-service config-provider --help
baijimu hosted-service config-binding --helpProvider registry 是动态目录。新增 object-storage Provider 不要求修改 Hosted Service contract、Hosted
Service Component 或 CLI;环境先安装对象存储 Package 并注册 Provider,项目再用 config-binding 保存自己的
profileRef。部署解析出的对象 API 地址和 Token 只进入目标 Environment,底层对象存储 AccessKey 不进入
Hosted Service 配置。
完整示例见 Hosted Service 对象存储与签名上传。
绑定数据库即生成默认配置
数据库 Profile 提供连接配置的来源。创建 Environment 数据库绑定时,平台同时生成
DATABASE_URL,来源为该绑定的 databaseUrl 字段;不需要再编写变量映射文件,也不需要复制连接密码。
绑定与默认配置在同一个事务、同一份环境修订中提交。随后部署,业务进程即可读取 DATABASE_URL。
已有运行中的进程需要重新部署才能使用新修订。
baijimu workspace hosted-service config-binding create \
--workspace-id WORKSPACE_ID --environment-id ENVIRONMENT_ID \
--name orders --provider-key DATABASE_PROVIDER_KEY --profile-ref DATABASE_PROFILE_REF同一环境绑定第二个数据库时,在绑定命令中指定变量前缀:
baijimu workspace hosted-service config-binding create \
--workspace-id WORKSPACE_ID --environment-id ENVIRONMENT_ID \
--name analytics --provider-key DATABASE_PROVIDER_KEY --profile-ref ANALYTICS_PROFILE_REF \
--variable-prefix ANALYTICS这会生成 ANALYTICS_DATABASE_URL。前缀只接受大写字母、数字和下划线,不能以数字开头或以下划线结尾。
省略前缀始终选择 DATABASE_URL,不会根据绑定顺序猜测主数据库。
若该变量已经指向相同绑定和字段,重复请求不会重复添加;若来自其他数据库、固定值或 Secret,整次绑定会报错,
保留原配置。相同绑定参数的重复请求返回原绑定;修改资源引用或其他绑定属性应使用 update。
默认规则由 Hosted Service 的版本化能力配置定义,当前数据库能力声明 DATABASE_URL ← databaseUrl。
配置中只保存资源引用,部署时再由 Provider 受控解析凭据并通过 Secret 通道注入。
历史绑定不会在发布时自动改写;对已有绑定再次提交相同 create 参数,可按相同冲突规则生成默认配置。
其他能力仍按各自配置合同选择字段。
自定义变量名称与来源
环境配置使用一个明确的变量列表。每个名称在环境内只能定义一次,来源可以是固定值、环境内资源绑定的字段、 Environment Secret,或资源绑定的调用凭据。Provider 返回哪些字段,不决定应用获得哪些环境变量。
数据库绑定已自动创建默认变量。需要添加其他变量或自定义名称时,可读取当前环境配置,保留已有变量,再提交完整配置文件。例如:
{
"schemaVersion": "1.0.0",
"variables": [
{ "name": "LOG_LEVEL", "source": { "kind": "literal", "value": "info" } },
{ "name": "DATABASE_URL", "source": { "kind": "resource", "binding": "orders", "field": "databaseUrl" } },
{ "name": "API_KEY", "source": { "kind": "secret", "key": "EXTERNAL_API_KEY" } }
],
"applicationConfig": { "featureEnabled": true }
}baijimu workspace hosted-service env update --workspace-id WORKSPACE_ID \
--environment-id ENVIRONMENT_ID --config-file ./environment.jsonenv update --config-file 替换完整环境配置;必须保留仍需使用的数据库变量,省略会删除该变量。
applicationConfig 是应用自己的不透明配置,作为 HOSTED_SERVICE_CONFIG_JSON 提供给进程;它的字段不会自动
变成环境变量。设置为 null 表示不提供这份应用配置。固定环境变量使用字符串。
资源字段只支持顶层字符串、数字、布尔值;嵌套对象、数组和空值不能隐式展开。同一个字段同时出现在 Provider
的 values 和 env 中会被视为歧义。变量只通过当前环境的绑定名称访问资源,不能填写任意 profileRef。
资源字段、Secret 和绑定凭据都通过 Secret 通道注入。绑定凭据使用
{ "kind": "bindingCredential", "binding": "workflow" } 作为来源,不再自动生成 WORKFLOW_TOKEN。
数据库默认变量在绑定时已写入配置。除此之外,没有声明的字段和 Secret 不注入;重复变量名、缺少绑定或字段、引用不存在的 Secret 都会报错。
绑定名由使用方定义,在环境内唯一。primary 没有特殊意义,同一个环境可以绑定多个数据库。配置引用中的
绑定名和迁移目标都必须有效;被当前配置或未完成迁移引用的绑定不能直接改名、停用或删除。
Environment Secret
每个 Project Environment 拥有独立的 Secret snapshot。Secret 只在所属 Environment 的配置和部署流程中可用, 不能跨 Environment 读取或复用。新增 Environment 后平台会自动创建对应 snapshot,不需要修改后端 Artifact、 额外登记密钥或调整组件版本。数据库 Profile 凭据仍由 Database Provider 根据绑定在部署时解析,不复制进 Environment Secret。
先读取当前键名和 Environment Revision。该操作只返回元数据,不返回任何 Secret 值:
baijimu workspace hosted-service env secret-get \
--workspace-id WORKSPACE_ID \
--environment-id ENVIRONMENT_ID更新使用显式 patch,并携带读取到的 version:
baijimu workspace hosted-service env secret-update \
--workspace-id WORKSPACE_ID \
--environment-id ENVIRONMENT_ID \
--expected-version ENVIRONMENT_REVISION \
--upserts-file ./secrets.json \
--remove-secret-key RETIRED_TOKEN \
--change-reason "rotate provider credential"--upserts-file 只写入或替换文件中出现的键,--remove-secret-key 只删除明确指定的键,其他现有键保持
不变。并发期间 Environment Revision 已变化时,服务端拒绝旧版本 patch;重新读取元数据并核对变更后再提交,
不要覆盖未知的新修订。
把历史普通配置迁移为 Secret 时,在同一次命令中传入 --remove-config-key NAME,并在 upsert 文件中提供
同名 Secret。普通配置删除、加密 Secret snapshot 和统一 Environment Revision 在同一个事务中提交;不能
把 --remove-config-key 当作普通配置删除接口。空 patch、隐式清空、写入与删除同一个键、删除不存在的键,
都会失败关闭。--remove-config-key 将同名固定变量原子改为 Secret 来源;Secret 存储键与变量名称属于不同
用途,只有显式声明的来源决定取哪个值,写入 Secret 不会覆盖同名固定变量。
Secret 值不会通过查询、更新响应或管理界面回显。敏感 JSON 应通过权限受控的临时文件或标准输入边界提供, 避免直接写在命令行、Shell 历史、项目 Git、Artifact、普通配置或日志中。更新只改变 Environment 配置源事实; 已有业务进程仍需通过受支持的重新部署或重启流程取得新 snapshot。
读取部署后的公开 Endpoint
Endpoint 的端口是 Runtime Revision 的平台事实,不属于业务配置。业务 Artifact 只声明 Endpoint 的数量、 稳定名称、协议和通用鉴权模式;部署时平台分配端口,并把每个端口拆分为业务进程环境变量。后端不需要解析 JSON 或根据 Project ID、环境 ID、域名格式和监听端口自行推导启动端口。
每个 Endpoint 都注入一个 APP_ENDPOINT_<NORMALIZED_NAME>_PORT,其中名称转换规则为:小写字母转为大写,
连字符 - 转为下划线 _。例如:
APP_ENDPOINT_API_PORT=20000
APP_ENDPOINT_MANAGEMENT_PORT=20001端口只在当前 Runtime Revision 内有效,示例值不固定。业务进程必须在固定的 127.0.0.1 上,使用对应
Endpoint 的命名端口变量启动 listener;不得使用或硬编码 APP_BIND_HOST、APP_PORT、PORT、BIND_ADDR、
listenPort 示例值或 proxyListenPort。平台不会注入这些变量,也不提供 APP_PORT 兼容注入。
Runtime 仍可能提供 RUNTIME_ENDPOINTS_JSON 作为 Endpoint 元数据,供确实需要读取 baseUrl 等公开信息的
适配器使用;它不是业务监听端口契约,业务启动不得依赖它解析端口。
固定健康检查协议
业务进程必须在每个声明的 HTTP Endpoint listener 上提供:
GET /healthz进程完成初始化并能够接收业务流量后返回 2xx;未就绪时返回非 2xx。/healthz 是 Hosted Service 的固定
协议常量,不属于 hosted-service.toml、Artifact Endpoint 元数据或 Environment 配置。平台不会读取或覆盖健康路径,
并拒绝任何健康路径覆盖字段。健康探针不执行 Endpoint consumer token 鉴权,
因此 handler 只能返回就绪状态,不应输出配置、凭据或业务数据。
当多个 Project Environment 共用一个 Slot Runtime 时,每个业务进程仍只会收到属于自身 Deployment 的 Endpoint,
并保留模块定义中的逻辑名称(例如 api)。Slot 父进程使用的命名空间前缀、访问令牌和其他
内部聚合字段不会进入业务进程的 RUNTIME_ENDPOINTS_JSON;若适配器读取该可选元数据,只能依赖下表定义的七个公开字段,
监听端口仍必须从对应的命名环境变量读取。
每个 Endpoint 对象包含以下字段:
| 字段 | 类型 | 含义 |
|---|---|---|
name | string | Endpoint 的稳定名称,例如 api 或 management |
protocol | string | Endpoint 协议;当前为 http |
listenPort | integer | Runtime 为该 Endpoint 动态分配的业务进程监听端口 |
routeHost | string | 平台为该 Endpoint 分配的路由主机名 |
baseUrl | string | 调用方可使用的完整公开基础 URL |
authMode | string | 该 Endpoint 当前采用的 Hosted Service 鉴权模式 |
primary | boolean | 是否为当前服务的主 Endpoint |
示例结构如下;实际值由当前部署动态生成:
[
{
"name": "api",
"protocol": "http",
"listenPort": 20000,
"routeHost": "example.app.baijimu.com.cn",
"baseUrl": "https://example.app.baijimu.com.cn",
"authMode": "none",
"primary": true
},
{
"name": "management",
"protocol": "http",
"listenPort": 20001,
"routeHost": "example-management.app.baijimu.com.cn",
"baseUrl": "https://example-management.app.baijimu.com.cn",
"authMode": "token",
"primary": false
}
]服务需要回传业务 API 地址时,应先按稳定语义选择 name == "api" 的 Endpoint;要求主入口时再同时校验
primary == true,并使用该对象的 baseUrl。缺少匹配项或存在多个匹配项应视为部署契约错误并停止启动,
不要猜测地址、退回旧属性值或从 routeHost 重新拼接 URL。
平台还会注入 RUNTIME_ENVIRONMENT_ID、RUNTIME_DEPLOYMENT_ID、RUNTIME_DEFAULT_USER_ID 和
RUNTIME_DEFAULT_WORKSPACE_ID,用于标识当前业务进程的部署与默认调用上下文。这些值和
RUNTIME_ENDPOINTS_JSON 都是平台拥有的运行时事实:即使环境普通配置、配置绑定或 Secret 中出现同名键,
最终注入值也以当前 Deployment 为准。命名 Endpoint 端口变量同样是平台拥有的运行时事实,业务进程必须为
自己声明的每个 Endpoint 读取对应命名端口,并在 127.0.0.1 上启动 HTTP listener。一个进程声明多个
Endpoint 时应在同一进程内绑定多个 listener,Runtime 仍只启动一个 OpenResty。listenPort 不能替代 baseUrl:
业务监听地址、Runtime 内部代理端口和公网调用地址是三个不同概念,只有 baseUrl 是调用方应保存和使用的稳定地址。
业务、管理与 Bundle 管理器生命周期入口
先按Bundle 管理器接入推荐架构确定协议由谁承载。 采用 Adapter 0.2.0 架构时,平台公开生命周期入口位于 Application Runtime 中 Adapter Bundle 自带的 Gateway。 网关通过 Adapter Module 验证 caller Token,再使用 Hosted Consumer 授权调用独立 Adapter 后端; Adapter 处理生命周期协议并调用业务 Hosted Service 的业务回调。Bundle 安装交付网关与标准模块方法, 后端进程、握手调度、凭据存储和数据库仍由独立 Hosted Service 承担,安装不会创建后端。 业务后端只实现业务回调,无需重复实现平台管理器协议。 以下 Endpoint 清单、listener 与登记步骤用于后端直接实现管理器协议;采用 Adapter Gateway 时, 管理器登记使用网关完整执行地址,Adapter 后端 Endpoint 保持 Hosted Token 保护,业务项目保留自己的业务 Endpoint。
设计后端时,先区分三类调用方,再声明 Endpoint。多租户服务如果需要随 Bundle 安装开通租户、 升级或配置时同步业务配置、卸载时解除绑定,必须提供供平台管理器登记服务调用的生命周期接口。 多租户本身不要求接入管理器;不参与这些操作的服务无需声明生命周期入口。
| 入口示例 | 调用方 | 职责与鉴权 |
|---|---|---|
api | 应用、模块、工作流、业务用户 | 执行业务请求,由业务后端识别租户、校验业务权限并隔离数据。 |
management | 服务运营人员、租户管理员 | 管理业务配置、账号或配额;分别校验租户内管理权限和跨租户权限。 |
lifecycle | 百积木管理器登记服务 | 执行获授权的 Bundle 生命周期操作,校验平台调用管理器的独立凭据和完整安装归属。 |
这三个名称是设计示例,不是平台保留名称,也不会自动生成 handler 或授予权限。 推荐将平台生命周期入口与业务入口、人工管理入口分开声明,便于独立路由和限制接口范围。 生命周期接口也可以与管理接口共用 listener,但必须按路由分别认证、授权,不能让管理器凭据获得所有管理能力。 管理器可以由业务服务直接实现,也可以由独立适配服务实现;后者只在自己的项目中声明执行入口。
在 Hosted Service 声明 Bundle 管理器的监听入口
下面是同一进程提供三类入口的完整清单示例。业务 api 使用 auth_mode = "none",由业务后端校验租户 token 和业务权限。后端从校验后的凭据确定租户,并按该租户隔离读写。
人工管理入口先通过 Hosted Service 入口鉴权,再校验管理员权限。生命周期入口校验平台调用 Bundle 管理器的专用 Bearer token。
contract_version = "3.0.0"
[service]
entrypoint = "target/release/example-service"
[[service.endpoints]]
name = "api"
protocol = "http"
auth_mode = "none"
primary = true
required = true
[[service.endpoints]]
name = "management"
protocol = "http"
auth_mode = "token"
required = true
[[service.endpoints]]
name = "lifecycle"
protocol = "http"
auth_mode = "none"
required = true业务进程分别读取 APP_ENDPOINT_API_PORT、APP_ENDPOINT_MANAGEMENT_PORT 和
APP_ENDPOINT_LIFECYCLE_PORT,在 127.0.0.1 启动对应 listener;每个 listener 都实现固定的
GET /healthz。不要硬编码端口,也不要为声明之外的入口猜测端口或回退到业务端口。
这是业务应用自己的监听入口,不是 Hosted Runtime 的运维或热更新管理端口。
lifecycle 示例使用 auth_mode = "none",只表示 Hosted Service 不校验 consumer token。
生命周期 handler 必须先验证 Authorization: Bearer <平台调用管理器的独立凭据>,再解析和执行请求;
缺失或错误凭据必须拒绝。该凭据通过受控服务端配置提供,不得复用业务租户 Token、人工管理 Token
或管理器调用平台的凭据。不要把这个示例直接改成 token 并复用管理密钥,否则会把两种独立认证合同混在一起。
声明多个端口不会自动建立网络隔离;实际可达范围以部署后的路由和访问策略为准。
从 Endpoint 到 Bundle 管理器登记
完整首次接入和验收以首次接入流程与验收为准。声明 listener 不会自动注册管理器;普通后端无需注册。 直接承载管理器协议时,按以下顺序衔接部署与握手:
- 实现当前管理器协议及认证,准备数据库和加密密钥。
- 用
baijimu workspace lifecycle-plugin register申请一次性授权,通过部署 Secret 及变量绑定交付。 - 部署或重启后,从
RUNTIME_ENDPOINTS_JSON选择实际承载协议的 Endpoint,将正式 HTTPSbaseUrl与真实 POST 路径组成执行地址。 不使用本机监听地址、动态端口或人工管理页面;不要根据 primary 标记猜测哪个入口实现了协议。 - 管理器持久化交换状态并完成握手,登记地址与阶段,建立双向凭据;CLI 的
complete-enrollment只回查结果。 - 移除一次性引导配置,保留身份和数据库密钥;验证无引导重启、轮换和鉴权,再进行业务 Bundle 联调。
采用 Runtime Gateway 的 Adapter 时,执行地址来自正式网关记录,按
Adapter 接入顺序准备调用链,不能套用直连 Endpoint 地址。
地址属于管理器登记目录,凭据属于受控存储,都不写入 Bundle。
AI 交付时报告实际 Endpoint、执行 URL、管理器身份、接入及业务验收结果,不输出凭据;单独 /healthz 通过不能证明管理器已接入。
Endpoint 鉴权
Hosted Service 支持两类边界:
authMode=token:由环境级 consumer 和绑定到当前 Endpoint 的 token 控制;Hosted Service 不解释 consumer 或 Endpoint 的业务用途。authMode=none:Hosted Service 不校验平台服务 token,业务应用必须自己实现完整鉴权。
Endpoint 鉴权只支持 none 和 token。Endpoint 名称仅用于稳定路由,不会把 management、primary
或其他名称转换成不同鉴权语义。
选择 none 不代表 Endpoint 自动安全,也不代表可以信任前端传入的用户身份。
管理 consumer 和 token 前先读取当前命令:
baijimu hosted-service consumer --help
baijimu hosted-service token --help
baijimu hosted-service auth-config --helptoken list 同时返回数字 id 和公开 tokenId。撤销时必须传 tokenId(例如 hsvc_...),数字 id
只是平台内部记录编号,不是撤销契约:
baijimu workspace hosted-service token list WORKSPACE_ID --environment-id ENVIRONMENT_ID
baijimu workspace hosted-service token revoke WORKSPACE_ID \
--environment-id ENVIRONMENT_ID \
--token-id TOKEN_ID删除 consumer 会在同一事务中撤销它的全部 token,并软删除 consumer;该操作必须显式确认:
baijimu workspace hosted-service consumer delete WORKSPACE_ID \
--consumer-id CONSUMER_ID \
--yes撤销不存在的 tokenId、删除不存在的 consumer,或操作不属于当前工作区的资源都会失败关闭,不会返回伪成功。
token 创建后只在安全位置保存。不要把它:
- 写入平台应用
accessUrl - 提交到项目 Git
- 返回给浏览器端长期保存
- 输出到构建或部署日志
Hosted Service Endpoint token 保护入站服务访问。后端调用 Bundle 资源时,使用生命周期交付的 ServiceReference 与对应资源的正式方法合同。 资源身份、调用凭据与业务用户委托分别校验,当前资源由各资源 Owner 提供。 旧 Bundle Capability 的全局 Token 和 Hosted 受管绑定已经退役。
接收 Runtime 调用上下文
后端作为模块方法的 HTTP 目标时,Runtime 不会自动向 Rust 服务注入 SDK 对象或完整上下文 JSON。模块必须
在 methodBody 中显式选择稳定上下文字段并映射到自己的 Header、Path、Query 或 Body;Rust 服务再在
HTTP 入口把映射结果转换成类型化请求上下文,并对必需字段失败关闭。
准确字段、出现条件、expression: "system.<字段名>" 映射,以及可直接使用的 Rust/Axum 提取示例见
模块调用上下文。自定义上下文
Header 不是 Endpoint 凭据;服务鉴权和业务用户授权仍需分别校验。
业务用户身份
服务 token 只回答“哪个调用方可以访问这个 Endpoint”,不自动回答“当前业务用户是谁、能操作哪些数据”。
平台应用调用后端应用时,应由受控网关传递已验证的工作区和用户上下文;后端应用不能把普通请求参数中的 userId 当成可信身份。管理员代办能力必须单独定义权限和审计。
接收 X-Baijimu-User-Assertion 的后端应用按获取平台用户断言公钥配置和刷新签发环境的 JWKS,再验证断言及业务授权。
后端同时作为模块方法目标,并按逻辑引用解析出的地址和凭据调用其他 Runtime 服务时,使用 Runtime 用户委托传递当前已验证用户:
- 入站请求存在
X-Runtime-Actor-Assertion时,只在当前请求内保存和转发; - 出站调用同时携带目标引用的 Bearer token 和该 assertion;
- 后端不签名、不解析、不记录 assertion,跨服务的下一跳轮换由 Runtime 完成;
- assertion 只对引用解析返回的
url有效,不能作为 Hosted Service 普通公开 Endpoint 的鉴权方式。