让密钥远离代码与日志

开发者的 AWS 安全实践

Rahul Singh

Technical Product Manager

并非所有敏感信息都是密钥

三类字符串

  • Secret: 陌生人可冒充您
  • 敏感数据: 可能暴露个人
  • 配置: 泄露无利可图

三行对比:secret、敏感数据和配置。每行给出两个示例值及陌生人可做之事,从冒充您到毫无收益。

开发者的 AWS 安全实践

并非所有敏感信息都是密钥

三类字符串

  • Secret: 陌生人可冒充您
  • 敏感数据: 可能暴露个人
  • 配置: 泄露无利可图

个人数据的两种称呼

  • PII: 可识别个人信息
  • PHI: 受保护的健康信息

三行对比:secret、敏感数据和配置。每行给出两个示例值及陌生人可做之事,从冒充您到毫无收益。

开发者的 AWS 安全实践

密钥外泄的四条路径

运行系统中的密钥分叉到四个编号出口:1 源代码及其历史,2 环境变量,3 应用日志,4 错误输出与追踪。四路最终汇聚到"可被他人读取"的方框。

  1. 源代码及其历史
  2. 环境变量
开发者的 AWS 安全实践

密钥外泄的四条路径

运行系统中的密钥分叉到四个编号出口:1 源代码及其历史,2 环境变量,3 应用日志,4 错误输出与追踪。四路最终汇聚到"可被他人读取"的方框。

  1. 源代码及其历史
  2. 环境变量
  3. 应用日志
  4. 错误输出与追踪
开发者的 AWS 安全实践

静态加密≠不可见

看似更安全的选择

  • 永远静态加密存储
  • AWS KMS 密钥,默认由 AWS 托管

一个 Lambda 函数包含环境变量,分成两路:磁盘上用 AWS KMS 静态加密(绿色);通过 API 的 GetFunctionConfiguration 调用明文返回(红色)。注释说明只有一路受保护。

开发者的 AWS 安全实践

静态加密≠不可见

看似更安全的选择

  • 永远静态加密存储
  • AWS KMS 密钥,默认由 AWS 托管

GetFunctionConfiguration 返回什么

  • 明文值

用存储答案回应访问问题

一个 Lambda 函数包含环境变量,分成两路:磁盘上用 AWS KMS 静态加密(绿色);通过 API 的 GetFunctionConfiguration 调用明文返回(红色)。注释说明只有一路受保护。

开发者的 AWS 安全实践

选哪个存储,为什么

两项服务,各司其职

  • Secrets Manager: 为密钥而生
  • Parameter Store: 为配置而生,SecureString 参数用 KMS 密钥加密

一个光谱图:左为 Secrets Manager,右为 Systems Manager Parameter Store,中间四条横轨,每条有编号标记:1 靠左端,2 略偏左,3 正中,4 靠右端;第四轨两端标注成本,旁注"轮换是关键决定因素"。

开发者的 AWS 安全实践

选哪个存储,为什么

两项服务,各司其职

  • Secrets Manager: 为密钥而生
  • Parameter Store: 为配置而生,SecureString 参数用 KMS 密钥加密

四件事决定选择

  1. 托管轮换
  2. 跨账户共享
  3. 版本管理
  4. 成本

一个光谱图:左为 Secrets Manager,右为 Systems Manager Parameter Store,中间四条横轨,每条有编号标记:1 靠左端,2 略偏左,3 正中,4 靠右端;第四轨两端标注成本,旁注"轮换是关键决定因素"。

开发者的 AWS 安全实践

新取短存,短暂缓存

运行中的进程在标记1 调用密钥存储的 GetSecretValue,标记2 使用仅限单个密钥 ARN 且含 kms:Decrypt 的最小权限角色,标记3 将返回值放入内存缓存,然后再调用数据库或合作方 API。

  1. 启动时调用 GetSecretValue
  2. 角色仅限一个密钥 ARN,外加 kms:Decrypt
开发者的 AWS 安全实践

新取短存,短暂缓存

运行中的进程在标记1 调用密钥存储的 GetSecretValue,标记2 使用仅限单个密钥 ARN 且含 kms:Decrypt 的最小权限角色,标记3 将返回值放入内存缓存,然后再调用数据库或合作方 API。

  1. 启动时调用 GetSecretValue
  2. 角色仅限一个密钥 ARN,外加 kms:Decrypt
  3. 在内存中缓存该值

缓存不失效,轮换会击穿您

开发者的 AWS 安全实践

轮换会在脚下换值

为何四步,而非一次切换

  • 新值在被任何人使用前已验证
  • 一次切换会同时弄坏所有客户端

三列纵向:轮换步骤、标签、以及您的缓存。Secrets Manager 依次运行 createSecret、setSecret、testSecret,虚线标记 finishSecret 移动标签的时刻。虚线上方标签"AWSCURRENT=旧值",缓存正确;下方标签"AWSCURRENT=新值",同一缓存被红色阴影标出。两种修复:缩短缓存寿命与在认证失败时刷新。

开发者的 AWS 安全实践

轮换会在脚下换值

为何四步,而非一次切换

  • 新值在被任何人使用前已验证
  • 一次切换会同时弄坏所有客户端

四步,一次交接

  • AWSPENDING、AWSCURRENT、AWSPREVIOUS

三列纵向:轮换步骤、标签、以及您的缓存。Secrets Manager 依次运行 createSecret、setSecret、testSecret,虚线标记 finishSecret 移动标签的时刻。虚线上方标签"AWSCURRENT=旧值",缓存正确;下方标签"AWSCURRENT=新值",同一缓存被红色阴影标出。两种修复:缩短缓存寿命与在认证失败时刷新。

开发者的 AWS 安全实践

轮换会在脚下换值

为何四步,而非一次切换

  • 新值在被任何人使用前已验证
  • 一次切换会同时弄坏所有客户端

四步,一次交接

  • AWSPENDING、AWSCURRENT、AWSPREVIOUS

缓存不会被通知

  • 以分钟为寿命,随后重读
  • 认证失败时触发刷新

三列纵向:轮换步骤、标签、以及您的缓存。Secrets Manager 依次运行 createSecret、setSecret、testSecret,虚线标记 finishSecret 移动标签的时刻。虚线上方标签"AWSCURRENT=旧值",缓存正确;下方标签"AWSCURRENT=新值",同一缓存被红色阴影标出。两种修复:缩短缓存寿命与在认证失败时刷新。

开发者的 AWS 安全实践

遮蔽与编辑,兼顾调试性

一行原始日志包含请求 ID、完整卡号和令牌,红框标出。下方为处理后的三项:请求 ID 保留,卡号仅留后四位,令牌以"已编辑"标记替代;旁注"保留足够信息便于调试"。

写入前先净化

  • 遮蔽(Mask): 保留形状,隐藏取值
开发者的 AWS 安全实践

遮蔽与编辑,兼顾调试性

一行原始日志包含请求 ID、完整卡号和令牌,红框标出。下方为处理后的三项:请求 ID 保留,卡号仅留后四位,令牌以"已编辑"标记替代;旁注"保留足够信息便于调试"。

写入前先净化

  • 遮蔽(Mask): 保留形状,隐藏取值
  • 编辑(Redact): 值移除,仅留标记
开发者的 AWS 安全实践

遮蔽与编辑,兼顾调试性

一行原始日志包含请求 ID、完整卡号和令牌,红框标出。下方为处理后的三项:请求 ID 保留,卡号仅留后四位,令牌以"已编辑"标记替代;旁注"保留足够信息便于调试"。

写入前先净化

  • 遮蔽(Mask): 保留形状,隐藏取值
  • 编辑(Redact): 值移除,仅留标记

值班需看配置,陌生人应看不到其余

开发者的 AWS 安全实践

让我们一起练习吧!

开发者的 AWS 安全实践

Preparing Video For Download...