Azure 密钥断层
按项目、环境和组处理 Azure 密钥默认密钥的节点库( 当金库是时) 和JSON一样 每一次失败都被分类和记录在它的级别, 图书馆说谁 它签了名 所以一个失踪的金库 无法进入的身份和失踪的秘密 一样.
无害环境管理,节点22.12或以后.
如何使用 QQ
import { AzureKeyVault } from '@achs/azure-key-vault';
// DefaultAzureCredential: environment variables, workload or
// managed identity, Azure CLI ("az login")...
const keyVault = new AzureKeyVault({
vaultUrl: 'https://my-key-vault.vault.azure.net',
project: 'my-project',
group: 'web',
env: 'dev',
});
await keyVault.setAll({
SECRET1: 'my secret 1',
otherConfig: { SECRET2: 'my secret 2' },
});
const secrets = await keyVault.getFor({
SECRET1: null,
otherConfig: { SECRET2: null },
SECRET3: 'default for secret 3',
});
// { SECRET1: 'my secret 1', otherConfig: { SECRET2: 'my secret 2' }, SECRET3: 'default for secret 3' }
// typed with the shape of the input: secrets.otherConfig.SECRET2
选项
| 选项 | 说明 |
|---|---|
vaultUrl | (字符串) 保险库 URL,即:. https://my-key-vault.vault.azure.net |
project | (弦)投射这些秘密属于 |
group | (弦) 秘密组 |
env | (弦)环境(德夫,qa,prod |
credential | (单位:千美元)TokenCredential任意 @azure/identity 证书,胜利 credentials |
credentials | (对象)服务本金 { clientId, clientSecret, tenantId }: 与 clientSecret,所有三个;没有它, DefaultAzureCredential 带 tenantId 财务报告和审定财务报表 clientId (工作量或管理下的身份)作为提示 |
logger | (对象) 登录器 trace, (中文(简体) ), debug, (中文(简体) ), info, (中文(简体) ), warn 财务报告和审定财务报表 error (主机,tslog |
logLevel | (字符串) 最低水平写入 : trace, (中文(简体) ), debug, (中文(简体) ), info, (中文(简体) ), warn, (中文(简体) ), error 或者说 silent |
strict | (布尔,默认) false(b) 保险库或访问失败投出,而不是只登录 |
concurrency | (数字,默认) 8请求一次输入 getFor, (中文(简体) ), getAll 编辑 *All 函数 |
timeoutMs | 每次行动的时限(数目),包括复试 |
dnsCheck | (布尔,默认) true在第一次请求之前解决金库主机(见下文) |
expiryWarningDays | (数字,默认) 30(b) 警告这些天内将到期的秘密; 0 关掉 |
clientOptions | (单位:千美元)SecretClientOptions) 秘密客户端的选项:重试,代理,用户代理. |
client | (单位:千美元)SecretClient秘密客户端,用于测试 |
仅具有某些值的服务本位值将丢入 TypeError,命名缺失的,和
无效 concurrency, (中文(简体) ), timeoutMs 或者说 expiryWarningDays 数值。 图书馆从来不写
process.env。 。 。 .
秘密名称
密钥地图 project-group-env-key小写 _ 空间变为 -
(单位:千美元)toSecretName(scope, key) 给它.
:(或--筑起一个键:car:props:name实值{ car: { props: { name } } }。 。 。 .- 最后一段从
$由项目的每个组(app)共用,相同 环境:parent:$global_var地图到project-env-parent--global-var不与 其他项目。 没有团体,KEY财务报告和审定财务报表$KEY映射到同一个秘密. - 不映射到有效秘密名称的密钥( 字母、 数字和破折号, 最多为 127) 失败
在任何请求之前; 以组表示范围包名称( x)
@scope/name也一样,所以设置AZURE_GROUP。 。 。 . - 范围(项目、组、环境)与名称相似,无论情况或空间如何
与(
normalizeScope:My App财务报告和审定财务报表my-app是一个组,标记是写入的 已经正常了.
标记
每个秘密都带有重建其关键和范围的标记(project, (中文(简体) ), group, (中文(简体) ), env, (中文(简体) ), name, (中文(简体) ), path, (中文(简体) ),
加:
| 标记 | 数值 |
|---|---|
managed-by | @achs/azure-key-vault/<version> 写的 |
updated-by | 谁写的:一个用户的上升, service-principal:<appId>, (中文(简体) ), managed-identity:<name> |
serialized | 1 jSON 值 (在 contentType(中文(简体) ) |
JSON 值( 除字符串外的任何东西) 也有 contentType: application/json,并在
要么这么说. updated-by 来源于该图书馆所签名的身份( 它需要一个符号)
); 使用注入的客户端时,它被忽略.
伐木和可追踪性
每一次失败都被分类(AzureKeyVaultErrorKind并登录在它的级别,命名金库和
它影响的秘密。 价值从来没有记录,只有秘密的名字.
| 仁爱 | 含义 | 职等 |
|---|---|---|
vault-not-found | 金库主机不解决(错误的 URL, 或拥有它的 DNS/ VPN) | 错误 |
vault-unreachable | 无法从金库( 网络、 代理、 TLS) 得到回复 | 错误 |
timeout | 手术花费的时间超过 timeoutMs | 错误 |
unauthenticated | 没有可用身份(未签名、服务本金错误、房客错误) | 错误 |
forbidden | 身份没有授权, 或保险库防火墙拒绝 | 错误 |
throttled | 金库油门请求(429个) 和回旋器已用完 | 错误 |
invalid-secret-name | 不映射到有效密名的密钥 | 错误 |
invalid-value | 标记为 JSON 的秘密,其值不解析,或未定义值 | 错误 |
unknown | 其他东西 | 错误 |
secret-not-found | 秘密不存在 | 警告( e) |
secret-disabled | 密钥已禁用 | 警告( e) |
每个关卡都显示:
- 错误/ 警告:每个原因各一行,每个秘密都会影响. A 类
forbidden线条名称 保险库里的人appid编号 :oid),操作需要的许可和作用 (单位:千美元)Key Vault Secrets User读取和列表,Key Vault Secrets Officer和谁的图书馆 签入. - 警告( e) 又: 读取已过期、 尚未生效的密件( 关键 Vault 无论如何都给它们) 或 关于
将到期的
expiryWarningDays) (中文(简体) ). - 资讯: 谁是图书馆注册的(
authenticated as user [email protected] (tenant ...)从 第一令牌:用户、服务主或管理下的身份,对多个操作的汇总 保密(read 3 of 5 secrets, 1 not found or disabled, 1 failed)和结果check()。 。 。 . - 调试:每个秘密读取,写出,删除,被清洗或恢复.
- 追踪:每个原因的原Azure SDK错误.
keyVault.identity 提供已知的身份(仅当库建客户端时).
木头去的地方
- 注入的
logger接收每个关卡并过滤自己,所以主机应用程序保存 所有东西都有一个日志级.@achs/env通过自己的 tslog 记录器这种方式。 设定logLevel改为 在这里过滤它. - 没有
logger图书馆用一个[akv]前缀,从logLevel, (中文(简体) ), 还有AKV_LOG_LEVEL环境变量,其他warn。 。 。 .
const keyVault = new AzureKeyVault({
vaultUrl,
project: 'my-project',
env: 'dev',
logger: parentLogger.getSubLogger({ name: 'akv' }),
});
失败和 strict
- 阅读和维修 (单位:千美元)
get, (中文(简体) ),getFor, (中文(简体) ),getAll, (中文(简体) ),keys, (中文(简体) ),versions, (中文(简体) ),delete, (中文(简体) ),purge, (中文(简体) ),restore编辑*All函数)记录其失败并继续:无法被读取的值 默认(或null) (中文(简体) ). 与strict: true时,错误级别失败会丢出一个AzureKeyVaultError一旦一切被记录下来,一个丢失或残废的秘密只会发出警告. - 写作 (单位:千美元)
set, (中文(简体) ),setAll, (中文(简体) ),rollback和getInfo总是扔一个AzureKeyVaultError。 。 。 .
import { AzureKeyVaultError } from '@achs/azure-key-vault';
try {
await keyVault.getFor(schema);
} catch (error) {
if (error instanceof AzureKeyVaultError)
console.error(error.kind, error.vaultUrl, error.secretNames);
}
classifyError(error) azure SDK 所抛出的任何错误.
check()
诊断一个金库 只有一个请求 一个不应该存在的秘密: 当金库通过它 主机解析和答案, 身份认证并可能读取机密, 上面写着是谁签名的 . 从来投出.
const { ok, kind, message, identity } = await keyVault.check();
// { ok: false, kind: 'forbidden', identity: { type: 'service-principal', appId: '...' }, message: 'https://...: the identity appid=... lacks the "get" secret permission (...), signed in as service principal appid=...' }
网络:DNS检查、VPN和代理
在首次请求之前,图书馆会解决一次库房主机 系统 DNS一个
每个请求的用途( VPN 包含的 DNS ) : 不同时解析失败的主机
vault-not-found,而不是在对每项请求进行重审之后。 它从来不违背要求,
与针对公共DNS服务器的检查不同,VPN可能会屏蔽. 当代理解决时它被跳过
改为主机(clientOptions.proxyOptions,或 HTTPS_PROXY编号 :HTTP_PROXY编号 :ALL_PROXY),带有
已注射 client,并与 dnsCheck: false。 。 。 .
concurrency 一次性封顶请求(一个共用的库门节流阀,它的所有呼叫者), timeoutMs
限制每个操作,和 clientOptions 到达 Azure 客户端(retries,代理). 用户代理
携带 @achs/azure-key-vault/<version>保险库的诊断记录显示是谁打来的.
职能
| 函数 | 说明 |
|---|---|
get(key, { version }?) | 隐藏值( 当存储为 JSON 时被分解), null 未读时; 如果给出了版本 |
getInfo(key) | 隐藏其属性; 投出失败 |
set(key, value) | 插入或更新一个密钥; 非字符串的值被存储为 JSON |
delete(key) | 删除一个秘密:删除的秘密, null 失败时 |
purge(key) | 清除被删除的秘密:是否被清除 |
restore(key) | 恢复被删除的秘密:其属性, null 失败时 |
versions(key) | 最新版本的秘密,没有价值; null 失败时 |
rollback(key, version) | 将上一版本( 值和标记) 写为当前版本 |
keys() | 项目组的按键, 排序, 无值( 需要) list(中文(简体) ) |
getFor(secrets, override?) | 读取一个值为默认对象的密件,按其形状键入 |
getAll() | 项目组的每一个秘密(列出整个金库:需要) list(中文(简体) ) |
setAll(secrets) | 插入或更新对象的秘密,顺序 |
deleteAll(skipShared = true) | 删除项目组的所有秘密 |
purgeAll(skipShared = true) | 清除项目组中每个被删除的秘密 |
restoreAll(skipShared = true) | 恢复项目组被删除的每一个秘密 |
check() | 诊断金库(见上文) |
audit({ allProjects }?) | 对项目(或整个金库)进行无读值的审计(见下文) |
getFor 只读默认为空的密钥( e)null, (中文(简体) ), '', (中文(简体) ), 0, (中文(简体) ), false),或每把键带有
override; 存储为 JSON (一个数组, 一个对象, 一个数字) 的秘密返回解析 .
const secrets = await keyVault.getFor({
'$global-var': null,
'my-secret': null,
'my-secret-2': 'default value',
'my-secret-group1': { 'my-secret-3': null },
'my-array-secret': null,
});
审计
audit() 为项目或
与 allProjects 整个金库,一个摘要(机密,由图书馆管理,贴上标签,不挂上标签,
(b) 将项目、小组(按环境分列)和这些结果记录在自己的层次:
| 查找 | 职等 | 含义 |
|---|---|---|
untagged | 警告( e) | 没有库标记的秘密( 隐形到 getAll 财务报告和审定财务报表 keys(中文(简体) ) |
shadowed | 警告( e) | 既拥有也共享的密钥($: @achs/env 将它们作为变量注入 |
scope-variants | 警告( e) | 一个以不同方式( 大小写, 空格) 写到的范围 : 它的秘密共享名称 |
name-mismatch | 警告( e) | 名称不是标记(改名,或用手标记) |
expired | 警告( e) | 过期机密 |
expiring | 资讯 | 秘密在内部终止 expiryWarningDays |
not-yet-valid | 资讯 | 他们的秘密 notBefore 未来 |
disabled | 资讯 | 已禁用机密 |
unnormalized-scope | 资讯 | 带有首府或空格的瞄准镜标记( 在其下次写入时规范化) |
other-env | 资讯 | 带有环境的项目审计:项目在其他环境中的秘密 |
auditSecrets(properties, options) 对别处列出的秘密财产进行同样的检查.
用模型测试
createAzureKeyVaultMock(options, { faults }) 给一个管理者一个由每个人共享的内存金库
嘲讽,这失败 就像阿苏尔做的(一个缺失的秘密是一个 secret-not-found) (中文(简体) ). faults 注入失败
键,或每个请求 '*'· ; resetAzureKeyVaultMock() 空出金库.
const vault = createAzureKeyVaultMock(
{ project: 'app', env: 'dev' },
{ faults: { DB_PASS: 'forbidden', '*': 'timeout' } },
);
命令 {}
这个 akv 命令运行相同的操作。 日志转到 stderr (at info 除非 --log 说
否则),输出为 stdout.
| 选项 | 说明 |
|---|---|
--uri | (需要) 保险库 URL |
--project | (所需)项目名称 |
--group | 秘密组 |
--env | 环境 |
--spn | 服务本金(申请)d |
--password | 主要机密服务 |
--tenant | 租户代号 |
--log | trace, (中文(简体) ), debug, (中文(简体) ), info (违约), warn, (中文(简体) ), error 或者说 silent |
--strict | 一个金库或访问失败失败命令 |
--concurrency | 一次请求 |
--timeout | 每次操作的时限,以毫秒计 |
--no-dns-check | 在第一次请求前跳过解析金库主机 |
--key | 密钥( e)get, (中文(简体) ), set, (中文(简体) ), versions, (中文(简体) ), rollback(中文(简体) ) |
--value | 隐藏值 set (从stdin读出) |
--version | 密语版本( e)get, (中文(简体) ), rollback(中文(简体) ) |
--file | 输入 JSON 文件( 相对于工作目录) |
--output | 输出 JSON 文件( 相对于工作目录) |
--override | getfor 读取带有默认值的密钥 |
--json | check 财务报告和审定财务报表 audit 以 JSON 打印结果 |
--all | audit 覆盖整个金库(无) --project (所需) |
| 命令 | 说明 |
|---|---|
check | 诊断金库,谁签入 |
audit | 审计项目或金库 --all· ; --strict 警告失败 |
get | 打印一个秘密值( 当它不是一个字符串时) |
set | 写出一个秘密; 管道值 (--value 会留在壳体历史) |
list | 打印工程组的密钥, 每行一个 |
versions | 打印一个秘密的版本为 JSON, 首先是 |
rollback | 将上一版本写为当前版本 |
getfor | 写入 --output 拥有秘密 --file 结构(值为默认值) |
getall | 写入 --output 项目组的每一个秘密 |
publish | 创建或更新 --file |
clear | 删除项目组的所有秘密 |
restore | 恢复项目组被删除的每一个秘密 |
退出代码 : 0 成功吗, 2 未找到金库,无法到达或超时, 3 无可用身份, 4
拒绝许可, 1 其他的任何东西。 仅读出命令失败 --strict (或何时) get, (中文(简体) ),
list 或者说 versions 读作"无".
akv check --uri=https://my-key-vault.vault.azure.net --project=my-project --env=dev --json
printf '%s' "$DB_PASS" | akv set --uri=... --project=my-project --env=dev --key=DB_PASS
akv getfor --uri=... --project=my-project --env=dev --file=structure.json --output=secrets.json --log=debug
runCli(argv) 从代码运行相同的命令,以及 exitCode(kind) 绘制其代码的失败类型.
联合国
pnpm test:cov # Vitest with coverage (100% thresholds)
pnpm lint # ESLint
pnpm typecheck # TypeScript
pnpm format # Prettier
pnpm build # Vite library build into dist/
变换日志 QQ
上一次更改见 变动情况。 。 。 .
由 QQ 建造
- @azure/身份 - Azure身份提供商.
- @azure/ keyvault- 机密 - Azure 键断层 秘密客户.