项目接入 vault¶
消费方项目怎么用 vault 里的凭证和资源。
流程一览¶
vault.json ← 你写(声明要什么)
↓ vault install (不传 --env · 一气出多份)
.env + .vault/secrets.json ← env-agnostic (顶层 slug 凭证)
.env.<name> + .vault/secrets.<name>.json ← 每个 envs.<name> 声明对应一份
↓
代码直接读 (按 process.env.APP_ENV 选)
vault install 行为:
| 调用 | 输出 |
|---|---|
vault install (不传 --env) |
env-agnostic .env + .vault/secrets.json + 每个 envs.<name> 声明对应的 .env.<name> + .vault/secrets.<name>.json 一气全出 |
vault install --env staging |
只装这一份: .vault/secrets.staging.json + .env.staging |
vault install --env prod |
只装这一份: .vault/secrets.prod.json + .env.prod |
env-agnostic .env: 只装顶层 slug 的凭证 (env 不区分)。envs.{...} 块声明的多环境凭证在这里跳过 (要 env 上下文才能定 slug)。
1. 初始化¶
在当前目录生成空骨架:
{
"$schema": "https://vault-cli.local/schemas/vault-manifest.schema.json",
"project": "myproject",
"credentials": {},
"resources": []
}
2. 声明依赖¶
编辑 vault.json,声明你需要的 credentials 和 resources。
{
"$schema": "https://vault-cli.local/schemas/vault-manifest.schema.json",
"project": "xiangqin",
"vault_min_version": ">=0.3",
"credentials": {
"aliyun": {
"slug": "aliyun-main",
"fields": ["access_key_id", "access_key_secret", "default_region"],
"env": {
"access_key_id": "ALIYUN_ACCESS_KEY_ID",
"access_key_secret": "ALIYUN_ACCESS_KEY_SECRET",
"default_region": "ALIYUN_REGION"
},
"purpose": "OSS 备份 + DNS 记录"
},
"alipay": {
"slug": "alipay-kongxuanpin",
"fields": ["app_id", "app_private_key", "alipay_public_key"],
"env": { "app_id": "ALIPAY_APP_ID" },
"optional": true
}
},
"resources": [
{ "ref": "aliyun/ecs/i-bp1iswr9bmkv3qh89965", "purpose": "生产服务器" },
{ "ref": "aliyun/oss/myproject-backup", "purpose": "每日备份" }
]
}
credentials 字段说明¶
| 字段 | 必填 | 说明 |
|---|---|---|
slug |
✓ | vault 里的 credential slug(vault credential list 查) |
fields |
白名单字段;不填 = 取全部 | |
env |
vault字段名 → ENV_NAME 映射;只列出的进 .env |
|
optional |
true 时凭证缺失只报 warning,不报错 | |
purpose |
人类可读注释 |
map 的 key 是本地别名¶
credentials.aliyun 里的 aliyun 是你代码里用的本地别名。底下挂的 slug: aliyun-main 是 vault 里的真名。别名层解耦了代码和 vault 命名变动。
resources 只声明不注值¶
Resource 只为 audit + vault who-uses 反查存在,不会把 spec 注入到代码。需要用时 vault resource show <ref>。
nested values(1 层 dict)¶
credential 的 values 支持 1 层 nested。常见场景:
- 多环境 db(prod / staging / canary 各一组 user/password)
- 多 client(web / mobile / cli 各一对 client_id/secret)
- 多 namespace 资源
vault 数据示例:
{
"slug": "hongniang-rds-mysql",
"kind": "misc",
"values": {
"endpoint": "rm.example.com",
"prod": { "db": "hongniang_prod", "user": "u_prod", "password": "..." },
"staging": { "db": "hongniang_staging", "user": "u_staging", "password": "..." }
}
}
vault.json 取值有两种写法:
{
"credentials": {
"db": {
"slug": "hongniang-rds-mysql",
"fields": ["endpoint", "prod"], // 整个 sub-dict
"env": { "prod.password": "DB_PASSWORD" } // dotted 取叶子(env 必须 scalar)
}
}
}
fields: ["prod"]→ secrets.json 里db.prod是完整 sub-dictfields: ["prod.password"]→ secrets.json 里db["prod.password"]是 scalarenv只接受 dotted 叶子 · sub-dict 会报错(env line 不能塞 JSON)
只支持 1 层 nested · prod.replica.user 不行(YAGNI · 真出现再升级)。
3. 多环境绑定(v0.3 polymorphic slug)¶
顶层 environments 显式声明项目支持哪些 env · slug 形态自推断作用范围:
slug: "shared-slug"(string) → 全 env 共享 · 进.env+ 所有.env.*slug: { "staging": "...", "prod": "..." }(object) → keys 即作用范围 ·.env跳过 · 只进 keys 列的 env 文件
{
"project": "akong",
"environments": ["staging", "prod"],
"credentials": {
"mysql": {
"slug": {
"staging": "akong-mysql-staging-pw",
"prod": "akong-mysql-prod-pw"
},
"fields": ["host", "port", "user", "password", "db"],
"env": {
"host": "DB_HOST",
"port": "DB_PORT",
"user": "DB_USER",
"password": "DB_PASSWORD",
"db": "DB_NAME"
},
"purpose": "MySQL 真值跟环境走 · env var name 不变"
},
"jwt_secret": {
"slug": {
"staging": "akong-jwt-staging",
"prod": "akong-jwt-prod"
},
"fields": ["secret"],
"env": { "secret": "JWT_SECRET" },
"purpose": "JWT 环境独立 · 不能共享 prod secret"
},
"sms": {
"slug": {
"staging": "matchmaker-sms-main",
"prod": "matchmaker-sms-main"
},
"fields": ["access_key_id", "access_key_secret"],
"env": {
"access_key_id": "SMS_AK",
"access_key_secret": "SMS_SK"
},
"optional": true,
"purpose": "staging/prod 走阿里云 dysmsapi · 跨 env 用同 slug 时显式重复"
},
"aliyun_shared": {
"slug": "aliyun-main",
"fields": ["access_key_id", "access_key_secret"],
"env": {
"access_key_id": "ALIYUN_AK",
"access_key_secret": "ALIYUN_SK"
}
}
}
}
4. 安装¶
vault install # 一气出: .env + .vault/secrets.json + 每个 envs.<name> 对应文件
vault install --env staging # 只装这一份: .vault/secrets.staging.json + .env.staging
vault install --env prod # 只装这一份: .vault/secrets.prod.json + .env.prod
输出:
✓ vault.json → 3 credentials (env=staging)
.vault/secrets.staging.json
.env.staging (6 env lines)
.gitignore (added .vault/ + .env + .env.*)
生成的文件:
.vault/secrets.<env>.json(结构化,按别名分组):
{
"_generated_at": "2026-04-22T13:35:40+00:00",
"_env": "staging",
"_note": "Auto-generated by `vault install --env staging` from vault.json. Do not edit.",
"mysql": {
"host": "rm-bp1xxx.mysql.rds.aliyuncs.com",
"port": 3306,
"user": "akong_staging",
"password": "...",
"db": "akong_staging"
},
"jwt_secret": { "secret": "..." }
}
.env.<env>(扁平,12-factor 风格):
DB_HOST=rm-bp1xxx.mysql.rds.aliyuncs.com
DB_PORT=3306
DB_USER=akong_staging
DB_PASSWORD=...
DB_NAME=akong_staging
JWT_SECRET=...
5. 代码里使用¶
代码按当前环境(NODE_ENV / APP_ENV / 部署管道传入)读对应文件即可 — env var name 不变 · 代码无感知。
Python¶
import json, os
env = os.environ.get("APP_ENV", "local")
# 方式一:结构化
secrets = json.loads(open(f".vault/secrets.{env}.json").read())
host = secrets["mysql"]["host"]
# 方式二:环境变量(先 dotenv.load_dotenv f".env.{env}" 或 systemd EnvironmentFile)
host = os.environ["DB_HOST"]
Node¶
import fs from "fs";
import "dotenv/config"; // 配合 dotenv-cli: dotenv -e .env.${APP_ENV}
const env = process.env.APP_ENV || "local";
const secrets = JSON.parse(fs.readFileSync(`.vault/secrets.${env}.json`));
const host = secrets.mysql.host;
// 或
const host = process.env.DB_HOST;
Shell¶
source ".env.${APP_ENV:-local}"
echo $DB_HOST
# 或直接 jq
jq -r '.mysql.host' ".vault/secrets.${APP_ENV:-local}.json"
6. 刷新(AK 轮换后)¶
7. 反查¶
哪些项目在用某个 credential?
vault who-uses aliyun-main
# /Users/yarnb/xiangqin/vault.json (credential (alias=aliyun))
# /Users/yarnb/myproject/vault.json (credential (alias=aliyun))
gitignore¶
vault install 自动把 .vault/ + .env + .env.* 加到 .gitignore(如果还没有)。
CI / 生产环境¶
生产部署时按目标环境跑 vault install --env staging/--env prod 把对应凭证拉到服务器。或者把 .vault/secrets.<env>.json 内容作为 secret manager 的变量(按平台约定)。
GHA 例:
- run: vault install --env staging # develop 分支 → staging
- run: vault install --env prod # main 分支 → prod
老格式平滑迁移¶
v0.2 完全 backward-compat 老格式 vault.json(无 envs 字段):
| 老格式 | 新行为 |
|---|---|
vault install(无 --env) |
写 .vault/secrets.local.json + .env.local |
顶层 slug |
任意 --env 都读这个 slug |
迁移方式:哪个 alias 真有多 env 用 envs.{local,staging,prod}.slug 重写,剩下保持单 slug 即可。