秘诀
由 AWS 保密管理器支持的单一应用程序秘密 .
何时使用 : 您需要存储一个高值证书——第三方API密钥,OAuth客户端秘密,数据库连接字符串,webhook签名密钥,或加密密钥. 每个 Secret 实例映射到 完全一个 机密管理器 .
不使用时 : 对于非敏感配置( 地标、 API URL、 阈值) 使用 AppSetting 标准值是免费的。 对于应用程序状态, 使用 KVStore 或者说 DistributedTable。 。 。 .
Secret被推荐为生产秘密之家. 对于任何保护生产应用的证书——数据库连接字符串,API密钥,OAuth令牌,或私人密钥——使用Secret它专为秘密而设:一个专门的每个秘密资源,有自己的访问控制、交叉账户共享、版本历史和(未来)有管理的轮换。 这个镜子 AWS本身的指导 关于全权证书的归属.
AppSetting与secret: true也可以在休息时加密该值并且是免费的,所以对于一个 低值 或当你想避免每笔秘密费用时 但为了保护一个生产应用, 接触Secret。 。 。 .
设计与模拟/ AWS 均等细节 : 设计
API 密码
const secret = new Secret(scope, id, options?)
| 方法 | 回返 | 说明 |
|---|---|---|
get(options?) | Promise<T | null> | 读取出值. null 当未设置/ 丢失. options.version 选择 'current' (违约), 'previous',或一个 SecretVersion 从 listVersions()。 。 。 . |
put(value) | Promise<void> | 在运行时设置或更新值 . 当秘密被创造时才出现 allowRuntimeWrite: true ——否则它不在对象(和类型)中. 前一个值变为 'previous' 版本. |
listVersions() | Promise<SecretVersionInfo[]> | 列出保留版本(仅元数据,最新第一——永远不值). |
Secret.fromExisting(arn) | ExternalSecretRef | 引用已有的秘密管理器机密( static) 。 传到 options.secret。 。 。 . |
选项
| 选项 | 类型 | 需求 | 说明 |
|---|---|---|---|
name | string | 没有 | 明确的秘密管理者的秘密名称。 省去时,取自瞄准镜树(每堆独有). 提供一个众所周知的名称,当一个团队/CI管道通过 aws CLI(英语:CLI). 设置时您拥有整个账户/区域的独特性 。 已忽略 fromExisting。 。 。 . |
allowRuntimeWrite | boolean | 没有 | 默认为 false。 。 。 . 何时 false秘密是... ... 秘密是... ... 秘密是.. 运行时只读: 无 put() 在对象上的方法,执行角色得到只读的 IAM(无) PutSecretValue) (中文(简体) ). 设定 true 只当应用程序在运行时设定/旋转值本身时——然后 put() 现在在场,并撰写IAM。 适用于每个秘密,包括 fromExisting。 。 。 . |
schema | StandardSchemaV1<T> | 没有 | 运行时验证计划 (Zod, Valibot, ArkType). 推断 T,将存储值作为 JSON 处理,并验证 get()编号 :put(). Omit 表示不透明 string。 。 。 . |
secret | ExternalSecretRef | 没有 | 将已有的秘密管理器密钥从 Secret.fromExisting(arn) 而不是创造一个. |
generate | boolean | 没有 | 何时 true,在第一个创建时种子随机值(对于只需要存在的签名/HMAC密钥)。 否则秘密就空了 get() 返回时 null 直到设定。 别和 schema。 。 。 . |
cacheTtlSeconds | number | 没有 | 运行时间重用一个缓存值后再调试多久 . 默认为 300s (5分钟),匹配 AWS 秘密管理器代理 —— 一种被限制的默认,所以一个长期运行的过程不能无限期地为旋转值服务. 把它抬起来切取取来, 放下来换新书, 或者设定 0 以禁用缓存. put() 总是清除缓存。 被模拟器忽略了. |
removalPolicy | 'destroy' | 'retain' | 没有 | 覆盖创建的秘密的堆积宽删除默认值 。 被模拟器所忽略,在包装已存在的秘密时被忽略. |
logger | ChildLogger | 没有 | 内部操作的可选日志。 默认为错误级别日志 . |
默认情况下只读( E)allowRuntimeWrite(中文(简体) )
A 类 Secret 实值 运行时只读,除非您选择加入。默认情况下,即时对象只曝光 get() 财务报告和审定财务报表 listVersions() 没有 put() (一个调用是一个编译错误),部署的执行角色被授予只读 IAM. 这是最小的特权: 多数应用读取一个证书 设置出带( Console, aws CLI,或CI),所以运行中的应用程序从不需要写入访问.
// Read-only (default): no put(). Set the value out-of-band, read it with get().
const stripeKey = new Secret(scope, 'stripe-api-key');
const key = await stripeKey.get();
// stripeKey.put('…') ❌ compile error — put is absent
// Writable: the app sets/rotates the value itself. put() is present; the role
// is granted PutSecretValue.
const token = new Secret(scope, 'self-rotating-token', { allowRuntimeWrite: true });
await token.put('t-abc123');
这也适用于通过下列途径包裹的秘密: fromExisting - 除非你通过,否则只读 allowRuntimeWrite: true。 。 。 .
处理错误
import { isBlocksError } from '@aws-blocks/core';
import { Secret, SecretErrors } from '@aws-blocks/bb-secret';
const secret = new Secret(scope, 'api-key', { allowRuntimeWrite: true });
try {
await secret.put(value);
} catch (e: unknown) {
if (isBlocksError(e, SecretErrors.ValidationFailed)) {
// schema validation failed
}
if (isBlocksError(e, SecretErrors.SecretNotFound)) {
// the underlying Secrets Manager secret does not exist
}
throw e;
}
get() 返回时 null 对于一个缺失的值而不是抛出,所以一个缺失的秘密是正常的控制流,而不是例外:
const key = await stripeKey.get();
if (key === null) throw new Error('Stripe key not configured');
实例
自动生成签名密钥( 应用程序创建值)
过 generate: true 并且从不设定一个值 —— 秘密管理器在第一次部署时创建了随机的(模拟种子是本地的等值). 对JWT/会话签名密钥或HMAC密钥有好处,其中应用程序生成了秘密,没有人需要读取.
const signingKey = new Secret(scope, 'session-signing-key', { generate: true });
export const api = new ApiNamespace(scope, 'api', (context) => ({
async issueToken(userId: string) {
const key = await signingKey.get(); // random value, created on first deploy
// sign(userId, key)...
},
}));
无
generate: true,一个 BB 创建的秘密开始 空数字 :get()返回时null直到设置一个值。 不要结合generate与schema——随机字符串无效JSON.
手动配置的证书( 您设置外部发行的值)
第三方密钥( Stripe, OAuth 客户端秘密) 是 没有 自动生成 —— 部署后设置出带. 宣言是相同的;区别在于有人提供了价值.
const stripeKey = new Secret(scope, 'stripe-api-key');
export const api = new ApiNamespace(scope, 'api', (context) => ({
async charge(amount: number) {
const key = await stripeKey.get();
if (key === null) throw new Error('Stripe key not configured');
// use key...
},
}));
设定一次值——通过设置控制台路由,部署脚本,或AWS CLI(参见"管理秘密值"). 如果应用程序本身在运行时更新了值, 请用 allowRuntimeWrite: true 打电话 put()数字 :
const stripeKey = new Secret(scope, 'stripe-api-key', { allowRuntimeWrite: true });
await stripeKey.put('sk_live_...');
使用 chema 验证方式输入的 JSON 秘密
import { z } from 'zod';
const dbConfig = new Secret(scope, 'db-config', {
schema: z.object({ host: z.string(), port: z.number() }),
});
export const api = new ApiNamespace(scope, 'api', (context) => ({
async connect() {
const config = await dbConfig.get(); // { host: string; port: number } | null
if (config === null) throw new Error('DB config not set');
// connect(config.host, config.port)...
},
}));
环绕已存在的密钥
const legacy = new Secret(scope, 'legacy-key', {
secret: Secret.fromExisting('arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-AbCdEf'),
});
const value = await legacy.get();
AWS Blocks 将不会创建,种子,或删除被引用的秘密——它只读取其值(并在 allowRuntimeWrite: true)并授予应用程序访问权限.
管理秘密价值
A 类 Secret 声明只包含 名称 从不值钱。 如何设定值取决于如何集中管理机密. 有三种相辅相成的办法:
1. 自动生成(随机)——无值设置
过 generate: true 永远不要打电话 put(): 秘密是用一个 随机值 首次部署(模拟种子在当地具有等值)。 用于不透明值, 没有人需要知道 —— 会话签名密钥, HMAC密钥 。 读出来 get();在调用之间稳定。 无 generate: true 隐藏开始为空 get() 返回时 null 直到您设定一个值.
2. 通过设置端点 控制台设置——大多数应用程序的默认值
每个AWS Blocks 应用程序曝光内置 /aws-blocks/settings 路线。 部署后,它会转向堆栈 设置 资源组在 AWS 控制台中,在其中 Secret 值与您的 AppSetting 参数 – 在控制台 UI 中设置或旋转它们. 在本地, 同一路线打开 .bb-data/settings.json,其中秘密值位于设置相邻处(plantext, dev-ext)。 一个路线,一个地方,地方和部署.
3. 众所周知 name +该 aws CLI——用于CI/CD驱动的工作流程
如果你的部署模式是脚本, 给秘密一个明确,稳定 name 并用标准的 AWS CLI 设置/旋转. 值会通过 AWS API 运行机器 → 秘密管理器; 它从不进入源, git, 或 Cloud Formation 模板 .
const stripeKey = new Secret(scope, 'stripe-key', { name: 'my-app/stripe-key' });
# Set / rotate — value over stdin, never argv or shell history.
printf '%s' "$STRIPE_KEY" \
| aws secretsmanager put-secret-value \
--secret-id my-app/stripe-key \
--secret-string file:///dev/stdin \
--region us-east-1
# Inspect (metadata only; the value requires explicit get-secret-value perms).
aws secretsmanager describe-secret --secret-id my-app/stripe-key
块应用程序 创建 部署时的秘密(空/随机),所以值被设定在一个已经存在的秘密上——一旦秘密存在就运行CLI. 你输油管里的确切顺序由你决定 重运行 put-secret-value 覆盖( 旋转); 当缓存副本过期时, 运行中的实例拾取新值( r)cacheTtlSeconds,默认为300 s). 写给 同一区域 应用程序部署到或读取一个未设定的秘密.
没有明确的 name,该秘密名称来源于瞄准镜树;在设置资源组、控制台或 aws secretsmanager list-secrets。 。 。 .
旋转并删除
- 旋转 : 设置新值( 控制台或
put-secret-value); 已缓存旧值的温和运行时间会在其缓存条目到期后收回变化(cacheTtlSeconds,默认为300 s)——不需要重新部署。 (单位:千美元) A 类put()从应用程序中清除了缓存 - 删除 :
aws secretsmanager delete-secret --secret-id <name>(默认可收回;--force-delete-without-recovery以跳过恢复窗口).
哪种方法,何时
| 假设 | 方针 |
|---|---|
| 中央管理的证书 数量 应用程序安装 | fromExisting(arn) ——参考;应用程序从不拥有或设置 |
| 普通应用程序, 部署后设定值一次 | 设置终点 – 控制台 (办法2) |
| 脚本/CI/CD驱动提供 | 众所周知 name + 键 aws CLI(办法3) |
| 一个不透明的值 没有人需要读 | 自动生成( 方法 1) |
有故意的,有故意的,没有故意的 没有 如何通过构建器从源代码或环境变量中种子一个秘密值——一个字词在源代码和模板中会降落,而env-seed被保留在声明之外(与托管方式一致)
secret()分离 声明 从 设定。通过控制台或CLI设置值.
读取更早的版本( 旋转宽度窗口)
每项更改均保留先前的数值作为 上一个 版本。 这在关键的推出过程中是有用的:在宽限期内验证新值和旧值.
const current = await signingKey.get(); // live value
const previous = await signingKey.get({ version: 'previous' }); // value before the last change, or null
// verify(token, current) || (previous !== null && verify(token, previous))
get({ version: 'previous' }) 返回时 null 直到秘密至少改变一次 要浏览保留版本( 仅元数据—— 永远不值) , 使用 listVersions() 并递回一个回到 get()数字 :
const versions = await signingKey.listVersions();
// [{ versionId, stages: ['AWSCURRENT'], createdDate }, { versionId, stages: ['AWSPREVIOUS'], createdDate }]
const value = await signingKey.get({ version: versions[1] }); // read a specific version
对于任何更深于当前/上一对的(完整历史,自定义中接标签,由任意的ID来读取),直接使用AWS SDK来对抗这个秘密——BB覆盖了共同路径,使原始资源可以到达. 秘密的ARN已经暴露在 CDK 构造 (单位:千美元)secret.secretArn,在合成时可用) ——在您构建SDK客户端的地方通过;运行时/模拟课刻意不暴露AWS原始人.
缩放成本( AWS)
- 计费: 每个秘密每月0.40美元(按比例计时)+每一万API呼叫0.05美元. 没有免费等级.
- 延迟 : 每API调用低-10s-ms;运行时间缓存在进程中获取值,所以稳定状态读取会击中缓存,而不是API. 缓存值为
cacheTtlSeconds—— 说 默认5分钟 (匹配 AWS 机密管理器代理) —— 因此在 TTL 内部, 即使是在长期运行的过程中也会取出一个旋转的值; 提高它来切取, 或设置0以禁用缓存. - 通过量 : GetSecretValue scale 到千个请求/秒每个账户(默认配额,可葡萄干). 阅读是热门道路;
put()这是罕见的. - 值大小限制 : 每个秘密值64 KB.
- 版本历史 :
listVersions()返回时 标签 版本 — 当前 + 先前。 机密管理器在内部保留了额外的无标签版本(直到 > 100,从未去掉过去24h中创建的任何版本),但BB只会浮出水流/上;为AWS SDK提供深度历史的可及性. - 加密 : KMS 处于休息状态, 使用默认值
aws/secretsmanager键. - 我问: 架构赋予共同执行角色
secretsmanager:GetSecretValue+ 键ListSecretVersionIds被设定为单一机密(不是通配符).PutSecretValue获得许可 仅限 何时allowRuntimeWrite: true——默认只读. KMS根据需要授予机密管理员. - 删除 : 默认可收回(30天回收窗口);
--force-delete-without-recovery立即删除. - 删除策略跟随堆积
defaults(生产保留、沙盒销毁)removalPolicyBB创造的秘密被标记aws-blocks-stack=<stackName>(加入设置资源组);fromExisting秘密没有标记.
地方发展
模拟存储当前值为 简单文字 共享 .bb-data/settings.json (同一文件) AppSetting 以密钥键入 name 或者说 fullId)并登录一次性警告. 这就是为什么当地 /aws-blocks/settings 路径在设置的同时显示机密。 上一数值(用于 get({ version: 'previous' }) 编号 : listVersions()) 保存在一个小的 .bb-data/secret-versions.json 侧车-当前+仅前;更深的历史是AWS唯一的能力. 没错 没有 安全——从不在地方发展中使用真正的证书。 擦拭为 rm -rf .bb-data。 。 。 .
Secret 仅运行服务器侧。 在浏览器/客户端代码中导入和即时处理 SecretErrors.NotSupported ——浏览器中读取的秘密会暴露给客户端.