AWS Secrets Manager:如何在 Python Lambda 中设置机密并获取它们

发布: (2025年12月19日 GMT+8 14:52)
5 分钟阅读
原文: Dev.to

Source: Dev.to

管理敏感信息(如数据库密码、API 密钥和令牌)是构建安全云应用的关键环节。将机密硬编码在源代码或配置文件中是一种常见的反模式,会导致安全漏洞。

AWS Secrets Manager 提供了一种安全、可扩展且可审计的方式,在运行时动态存储和检索机密。本文将介绍:

  • 什么是 AWS Secrets Manager
  • 如何创建和存储机密
  • 所需的 IAM 权限
  • 如何在 Python AWS Lambda 中获取机密
  • 最佳实践

1. 什么是 AWS Secrets Manager?

AWS Secrets Manager 是一项托管服务,帮助您:

  • 安全存储机密(凭证、API 密钥、令牌)
  • 使用 AWS KMS 加密机密
  • 通过 IAM 控制访问
  • 自动轮换机密(针对受支持的服务)
  • 在运行时以编程方式检索机密

典型使用场景:

  • 数据库凭证(RDS、Aurora)
  • 第三方 API 密钥
  • JWT 签名密钥
  • OAuth 客户端密钥

2. 在 AWS Secrets Manager 中创建密钥

步骤 1:打开 AWS Secrets Manager

  1. 登录 AWS 控制台。
  2. 导航至 Secrets Manager
  3. 点击 存储新密钥

步骤 2:选择密钥类型

选择 其他类型的密钥 来存储自定义键/值对,例如:

DB_USERNAME = admin
DB_PASSWORD = StrongPassword@123
DB_HOST     = mydb.cluster-xyz.us-east-1.rds.amazonaws.com

Secrets Manager 将这些值存储为加密的 JSON。

步骤 3:配置加密

  • 选择默认的 AWS‑managed KMS 密钥,
  • 选择客户管理的 KMS 密钥以满足更严格的合规要求。

步骤 4:命名密钥

为密钥指定清晰且与环境相关的名称,例如:

  • myapp/dev/database
  • myapp/staging/database
  • myapp/prod/database

此命名策略可避免意外的跨环境访问。

步骤 5:审查并创建

点击 存储。您的密钥现在已安全存储。

3. Lambda 的 IAM 权限

您的 Lambda 函数必须拥有读取密钥的权限。

IAM 策略示例

将以下策略附加到 Lambda 执行角色:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:myapp/dev/database*"
    }
  ]
}

重要: 始终将 Resource 限定为特定的密钥,而不要使用 "*"

4. 在 Python Lambda 中获取 Secrets

步骤 1:Python 依赖

AWS Lambda 已经内置了 boto3botocore。无需额外的库。

步骤 2:获取 Secrets 的 Python 代码

import json
import boto3
from botocore.exceptions import ClientError

def get_secret(secret_name, region_name="us-east-1"):
    client = boto3.client(
        service_name="secretsmanager",
        region_name=region_name
    )

    try:
        response = client.get_secret_value(SecretId=secret_name)
    except ClientError as e:
        raise RuntimeError(f"Unable to retrieve secret: {e}")

    # Secrets are usually stored as JSON strings
    if "SecretString" in response:
        return json.loads(response["SecretString"])
    else:
        # Binary secrets (rare case)
        return response["SecretBinary"]

步骤 3:在 Lambda 处理函数中使用 Secrets

def lambda_handler(event, context):
    secret_name = "myapp/dev/database"

    secrets = get_secret(secret_name)

    db_user = secrets["DB_USERNAME"]
    db_password = secrets["DB_PASSWORD"]
    db_host = secrets["DB_HOST"]

    # Example usage
    print(f"Connecting to DB at {db_host} with user {db_user}")

    return {
        "statusCode": 200,
        "body": "Secrets fetched successfully"
    }

5. 性能考虑(重要)

每次调用 GetSecretValue 都会进行网络请求。为降低延迟和 API 使用量,请在模块级别缓存密钥:

_cached_secrets = None

def get_cached_secret(secret_name):
    global _cached_secrets
    if _cached_secrets is None:
        _cached_secrets = get_secret(secret_name)
    return _cached_secrets

6. 基于环境的密钥管理

使用环境变量来控制加载哪个密钥:

import os

secret_name = os.environ["SECRET_NAME"]   # e.g., myapp/dev/database
secrets = get_cached_secret(secret_name)

这使得:

  • 在 DEV / STAGE / PROD 环境中使用相同的代码库
  • 环境特定的密钥
  • 更安全的部署

7. Security and Best Practices

  • 永不硬编码密钥。
  • 使用最小权限的 IAM 策略。
  • 为每个环境保持独立的密钥。
  • 在支持的情况下启用自动轮换。
  • 在 Lambda 中缓存密钥以提升性能。
  • 谨慎记录日志——绝不记录密钥值。
  • 对于高度敏感的数据,优先使用 Secrets Manager 而非 SSM 参数存储。
Back to Blog

相关文章

阅读更多 »