

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 管理安全敏感型工作负载的 API 密钥
<a name="api-keys-security-sensitive"></a>

AWS Secrets Manager 帮助您在数据库凭证、应用程序凭证、OAuth 令牌、API 密钥和其他密钥的整个生命周期中管理、检索和轮换。本页为在安全敏感型工作负载中管理 API 密钥和第三方凭证提供规范性指导。将自动轮换与客户管理的 AWS KMS 密钥和最低权限 IAM 政策相结合。还要配置 VPC 终端节点访问权限，以最大限度地减少泄露凭证的暴露窗口和爆炸半径。

## 将 API 密钥存储在 AWS Secrets Manager
<a name="api-keys-storage"></a>

本节介绍如何构建 API 密钥以实现最佳轮换和检索。将每个 API 密钥存储为具有结构化 JSON 值的单独密钥。使用这种结构，您的应用程序可以检索单个字段，Secrets Manager 可以将正确的值传递给旋转函数。

以下示例显示了第三方 API 密钥密钥的常用 JSON 结构。实际字段取决于您的提供商的要求——请查看提供商的文档，了解您需要存储的特定凭证和元数据。

```
{
  "apiKey": "your-api-key-value",
  "apiKeyId": "key-identifier",
  "endpoint": "https://api.example.com/v1",
  "provider": "example-service"
}
```


**API 密钥的秘密结构示例**  

| 字段 | 示例值 | 用途 | 
| --- | --- | --- | 
| `apiKey` | `sk_live_abc123...` | 您的应用程序使用第三方 API 进行身份验证的凭据值。 | 
| `apiKeyId` | `key_001` | 提供商端的密钥标识符。在轮换期间用于创建新密钥和删除旧密钥。 | 
| `endpoint` | `https://api.example.com/v1` | API 终端节点 URL。使用密钥存储，因此检索会返回应用程序连接所需的所有内容。 | 
| `provider` | `stripe` | 提供商名称。可用于标记、筛选和旋转处理多个提供者的函数逻辑。 | 

使用元数据标记每个密钥以支持 IAM 策略条件和组织筛选。例如，您可以使用 AWS CLI 或控制台使用所属团队、环境和合规范围标记机密：

```
aws secretsmanager tag-resource \
    --secret-id prod/payments/stripe-api-key \
    --tags Key=Team,Value=payments Key=Environment,Value=production \
           Key=Provider,Value=stripe Key=Compliance,Value=pci-dss
```

有关创建密钥的更多信息，请参阅[创建一个 AWS Secrets Manager 机密密钥](create_secret.md)。

## 加密配置
<a name="api-keys-encryption"></a>

密钥管理器使用密钥对所有静态密 AWS KMS 钥值进行加密。对于安全敏感型工作负载，请根据您的合规性和访问控制要求选择加密密钥。


**API 密钥密钥的 KMS 密钥选项**  

| 密钥类型 | 何时使用 | 安全注意事项 | 
| --- | --- | --- | 
| AWS 管理密钥 (`aws/secretsmanager`) | 大多数工作负载的默认设置。没有额外的成本或密钥管理开销。 | 密钥策略仅限于凭据管理器操作，无法修改。不能用于跨账户访问。 | 
| 客户自主管理型密钥 | 合规性要求（例如，PCI DSS、HIPAA、SOC 2 或其他适用标准）。 Cross-account 秘密共享。密钥使用审计要求。 | 您可以控制密钥策略。您可以限制哪些委托人可以解密。您可以独立于密钥禁用或安排密钥删除。提供独立的审计跟踪。 | 

对于安全敏感型工作负载，使用具有以下关键策略条件的客户管理密钥：
+ `kms:ViaService`— 将密钥的使用限制为源自密钥管理器 (`secretsmanager.<region>.amazonaws.com`) 的请求。
+ `kms:EncryptionContext:SecretARN`— 通过匹配密钥管理器加密上下文，将解密限制为特定的机密 ARN。
+ 每个合规边界分开 AWS KMS 密钥 — 对不同合规范围内的密钥使用不同的密钥（例如，PCI 与非 PCI 的对比）。

有关加密和解密过程的完整说明，请参阅[中的秘密加密和解密 AWS Secrets Manager](security-encryption.md)。

## API 密钥的自动轮换
<a name="api-keys-rotation"></a>

自动轮换可减少泄露凭证的风险窗口。密钥管理器按计划调用 Lambda 函数。该函数在提供商处创建新的 API 密钥，更新机密值并删除旧密钥。

Secrets Manager 通过托管的外部密钥为一些第三方提供商提供托管轮换功能。有关此功能和支持的提供商列表的更多信息，请参阅[管理外部机密合作伙伴](mes-partners.md)。对于不支持托管轮换的提供商，您可以实现自定义 Lambda 轮换函数，该函数调用提供商的 API 来创建和删除密钥。

### 旋转函数生命周期
<a name="api-keys-rotation-function"></a>

旋转 Lambda 函数实现了四个步骤。密钥管理器为每个步骤调用一次该函数，并传递一个参数。`Step`如果任何步骤失败，Secrets Manager 会自动重试整个轮换。


**API 密钥的轮换步骤**  

| 步骤 | API 密钥的操作 | 故障处理 | 
| --- | --- | --- | 
| `createSecret` | 调用提供商 API 来创建新密钥。使用`AWSPENDING`暂存标签将新的密钥值存储在凭据管理器中。 | 如果密钥创建失败，则轮换不会进入下一步。现有密钥保持活动状态为`AWSCURRENT`。 | 
| `setSecret` | 对于在提供商处创建的 API 密钥，此步骤通常是无效的。此步骤用于在 Secrets Manager 中生成随机密钥并需要在提供商处设置——这不是典型的 API 密钥流程。 | 如果此步骤失败，则不会继续旋转`testSecret`。 | 
| `testSecret` | 从 Secrets Manager 检索`AWSPENDING`值，然后向提供商进行测试 API 调用，以验证新密钥是否有效。 | 如果测试失败，请删除提供商处的待处理密钥并引发异常。 | 
| `finishSecret` | 移`AWSCURRENT`至新密钥。旧密钥移至`AWSPREVIOUS`。（可选）删除提供商处的旧密钥。 | 如果标签更新失败，则轮换不会完成。新密钥已存在但尚未标记`AWSCURRENT`。 | 

有关完整的轮换功能模板和实施指南，请参阅[Lambda 轮换函数](rotate-secrets_lambda-functions.md)。

### 轮换时间表配置
<a name="api-keys-rotation-schedule"></a>

根据您的合规要求和内部安全策略设置轮换间隔。请参阅适用于您的工作负载的合规标准，以确定适当的轮换频率。

使用旋转窗口控制何时旋转。这样可以防止轮换在流量高峰或维护时段运行：

```
aws secretsmanager rotate-secret \
    --secret-id prod/payments/stripe-api-key \
    --rotation-rules '{
        "ScheduleExpression": "cron(0 4 ? * SUN *)",
        "Duration": "2h"
    }'
```

有关计划表达式语法，请参见[轮换计划](rotate-secrets_schedule.md)。

## 高效检索机密
<a name="api-keys-access-patterns"></a>

密钥管理器支持每秒`GetSecretValue`通话 10,000 笔交易。大多数应用程序都不会受到限制。对于调用量非常高或对延迟敏感的路径的应用程序，使用缓存解决方案来减少 API 调用并缩短响应时间。

Secrets Manager 提供多种语言的缓存客户端，以及在执行环境中本地缓存密钥的 Lambda 扩展。有关缓存选项的更多信息，请参阅[使用 Java 和客户端缓存获取 Secrets Manager 密钥值](retrieving-secrets_cache-java.md)[使用 Python 和客户端缓存获取 Secrets Manager 密钥值](retrieving-secrets_cache-python.md)、和[使用 Go 和客户端缓存获取 Secrets Manager 密钥值](retrieving-secrets_cache-go.md)。

对于所有访问模式，配置 IAM 策略，仅限`secretsmanager:GetSecretValue`于每个应用程序所需的特定密钥：

```
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "secretsmanager:GetSecretValue",
    "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/payments/*",
    "Condition": {
      "StringEquals": {
        "aws:ResourceTag/Environment": "production"
      }
    }
  }]
}
```

## 敏感工作负载的安全强化
<a name="api-keys-security-hardening"></a>

以下做法为具有严格安全要求的环境（例如 PCI DSS、SOC 2、HIPAA 或其他适用的合规框架）中的 API 密钥提供深度防御：

**使用 VPC 终端节点限制网络访问**  
为 Secrets Manager 创建接口 VPC 终端节点，这样秘密检索就不会遍历公共互联网。应用终端节点策略，限制可以通过终端节点访问哪些机密。有关更多信息，请参阅 [使用 AWS Secrets Manager VPC 终端节点](vpc-endpoint-overview.md)。

**将资源策略应用于机密**  
为每个密钥附加资源策略，明确拒绝您的账户之外或特定 VPC 终端节点之外的委托人进行访问。这提供了独立于 IAM 身份策略的第二个授权边界。

**使用监控秘密访问权限 **  
 自动记录所有 Secrets Manager API 调用`GetSecretValue`，包括`PutSecretValue`、和`RotateSecret`。对于安全敏感机密，创建在意外`GetSecretValue`调用时触发的 Amazon CloudWatch 警报，例如，来自无法识别的源 IP 地址或 IAM 委托人的呼叫。

**`AWSPREVIOUS`用于平滑旋转**  
在轮换期间，凭据管理器使用`AWSPREVIOUS`暂存标签保留先前的密钥值。如果您的提供商在创建新密钥时使先前的密钥无效，请将您的应用程序配置为在返回身份验证错误`AWSPREVIOUS`时`AWSCURRENT`退回。这样可以防止在密钥创建和标签更新之间的短暂时段内出现停机。

**在连接之前验证资源策略**  
没有资源策略的密钥已经阻止了公众访问。当您将资源策略附加到密钥时，请使用 `ValidateResourcePolicy` API 来确保您的策略不会授予广泛的公共访问权限。您也可以将`BlockPublicPolicy`参数与一起使用，`PutResourcePolicy`以防止附加授予公共访问权限的策略。在资源策略中使用`aws:PrincipalOrgID`条件密钥来防止组织外部的委托人访问。

## 常见问题
<a name="api-keys-faq"></a>

本节回答了有关 API 密钥轮替和密钥管理的常见问题 AWS Secrets Manager。

### 如何处理轮换期间的重叠期？
<a name="api-keys-faq-overlap"></a>

只有当提供者在创建新密钥时使现有密钥失效时，才需要这样做。如果提供商同时支持多个活动密钥，则两个密钥在轮换期间均可使用，而无需应用程序端的备用逻辑。对于使旧密钥失效的提供商，请将您的应用程序配置为在当前密钥返回 401 或 403 错误时重试。`AWSPREVIOUS`只有在确认新密钥有效后，才能在`finishSecret`步骤中删除提供商处的旧密钥。

### 如果我的提供商不支持编程密钥创建怎么办？
<a name="api-keys-faq-not-rotating"></a>

如果提供商需要手动创建密钥（例如通过 Web 控制台），则无法完全自动轮换。取而代之的是，使用轮换功能，在轮换到期时发送通知（通过亚马逊简单通知服务），提示操作员手动创建密钥并更新密钥值。设置轮换时间表以匹配您的合规轮换要求，并使用亚马逊 CloudWatch 警报`days_since_last_rotation`来检测错过的轮换。

### 检索机密时如何避免 API 限制？
<a name="api-keys-faq-throttling"></a>

密钥管理器支持每秒 10,000 笔交易`GetSecretValue`。大多数应用程序都不会受到限制。如果您的应用程序调用量异常高，请使用缓存客户端或 Lambda 参数和密钥扩展。它们将密钥值缓存到内存中并定期刷新，从而减少了 API 调用的次数。将缓存 TTL 设置为一个短于轮换间隔的值，以便应用程序在轮换后获取新密钥。

### 我应该在每个环境中使用一个密钥还是在版本中使用一个密钥？
<a name="api-keys-faq-multiple-environments"></a>

为每个环境使用单独的密钥（例如，`prod/payments/stripe`和`dev/payments/stripe`）。这允许每个环境使用不同的 IAM 策略、轮换计划和加密密钥。密钥版本（暂存标签）用于轮换状态管理，而不是环境分离。