aws-secrets-manager

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AWS Secrets Manager

AWS Secrets Manager

Securely store, manage, and rotate secrets in AWS.
在AWS中安全存储、管理和轮换密钥。

When to Use This Skill

何时使用此技能

Use this skill when:
  • Storing database credentials, API keys, or tokens in AWS
  • Implementing automatic credential rotation for RDS or other services
  • Replacing hardcoded secrets in application code or config files
  • Integrating secrets into ECS, EKS, or Lambda workloads
  • Meeting compliance requirements for secret management and rotation
在以下场景中使用此技能:
  • 在AWS中存储数据库凭证、API密钥或令牌
  • 为RDS或其他服务实现自动凭证轮换
  • 替换应用代码或配置文件中的硬编码密钥
  • 将密钥集成到ECS、EKS或Lambda工作负载中
  • 满足密钥管理与轮换的合规要求

Prerequisites

前提条件

  • AWS account with appropriate IAM permissions
  • AWS CLI v2 installed and configured
  • IAM policy allowing
    secretsmanager:*
    actions (or scoped permissions)
  • For rotation: Lambda execution role and VPC access to target services
  • Python 3.9+ with
    boto3
    for SDK examples
  • 拥有适当IAM权限的AWS账户
  • 已安装并配置AWS CLI v2
  • 允许
    secretsmanager:*
    操作(或限定范围权限)的IAM策略
  • 若要启用轮换:Lambda执行角色以及对目标服务的VPC访问权限
  • 安装了
    boto3
    的Python 3.9+环境(用于SDK示例)

Secret Creation and Management

密钥创建与管理

bash
undefined
bash
undefined

Create a secret with JSON structure

创建带JSON结构的密钥

aws secretsmanager create-secret
--name myapp/production/database
--description "Production database credentials"
--secret-string '{"username":"dbadmin","password":"S3cur3P@ssw0rd!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}'
--tags '[{"Key":"Environment","Value":"production"},{"Key":"Team","Value":"platform"}]'
aws secretsmanager create-secret
--name myapp/production/database
--description "Production database credentials"
--secret-string '{"username":"dbadmin","password":"S3cur3P@ssw0rd!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}'
--tags '[{"Key":"Environment","Value":"production"},{"Key":"Team","Value":"platform"}]'

Create a secret with KMS encryption (custom key)

使用KMS加密创建密钥(自定义密钥)

aws secretsmanager create-secret
--name myapp/production/api-key
--description "Third-party API key"
--secret-string "ak_live_xxxxxxxxxxxx"
--kms-key-id alias/secrets-key
aws secretsmanager create-secret
--name myapp/production/api-key
--description "Third-party API key"
--secret-string "ak_live_xxxxxxxxxxxx"
--kms-key-id alias/secrets-key

Create a binary secret (certificates, keys)

创建二进制密钥(证书、密钥)

aws secretsmanager create-secret
--name myapp/production/tls-cert
--secret-binary fileb://server.pfx
aws secretsmanager create-secret
--name myapp/production/tls-cert
--secret-binary fileb://server.pfx

Get secret value

获取密钥值

aws secretsmanager get-secret-value
--secret-id myapp/production/database
--query 'SecretString' --output text | jq .
aws secretsmanager get-secret-value
--secret-id myapp/production/database
--query 'SecretString' --output text | jq .

Get a specific version

获取特定版本的密钥

aws secretsmanager get-secret-value
--secret-id myapp/production/database
--version-stage AWSPREVIOUS
aws secretsmanager get-secret-value
--secret-id myapp/production/database
--version-stage AWSPREVIOUS

Update secret value

更新密钥值

aws secretsmanager put-secret-value
--secret-id myapp/production/database
--secret-string '{"username":"dbadmin","password":"N3wS3cur3P@ss!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}'
aws secretsmanager put-secret-value
--secret-id myapp/production/database
--secret-string '{"username":"dbadmin","password":"N3wS3cur3P@ss!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}'

List all secrets

列出所有密钥

aws secretsmanager list-secrets
--filters Key=name,Values=myapp/production
aws secretsmanager list-secrets
--filters Key=name,Values=myapp/production

Delete secret (with recovery window)

删除密钥(带恢复窗口期)

aws secretsmanager delete-secret
--secret-id myapp/production/old-key
--recovery-window-in-days 7
aws secretsmanager delete-secret
--secret-id myapp/production/old-key
--recovery-window-in-days 7

Restore a deleted secret

恢复已删除的密钥

aws secretsmanager restore-secret
--secret-id myapp/production/old-key
aws secretsmanager restore-secret
--secret-id myapp/production/old-key

Tag a secret

为密钥添加标签

aws secretsmanager tag-resource
--secret-id myapp/production/database
--tags '[{"Key":"RotationEnabled","Value":"true"}]'
undefined
aws secretsmanager tag-resource
--secret-id myapp/production/database
--tags '[{"Key":"RotationEnabled","Value":"true"}]'
undefined

Automatic Rotation

自动轮换

Enable Rotation

启用轮换

bash
undefined
bash
undefined

Enable rotation with an existing Lambda function

使用现有Lambda函数启用轮换

aws secretsmanager rotate-secret
--secret-id myapp/production/database
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSPostgreSQLRotation
--rotation-rules '{"AutomaticallyAfterDays":30,"ScheduleExpression":"rate(30 days)"}'
aws secretsmanager rotate-secret
--secret-id myapp/production/database
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSPostgreSQLRotation
--rotation-rules '{"AutomaticallyAfterDays":30,"ScheduleExpression":"rate(30 days)"}'

Trigger immediate rotation

触发立即轮换

aws secretsmanager rotate-secret
--secret-id myapp/production/database
aws secretsmanager rotate-secret
--secret-id myapp/production/database

Check rotation status

检查轮换状态

aws secretsmanager describe-secret
--secret-id myapp/production/database
--query '{RotationEnabled:RotationEnabled,RotationLambdaARN:RotationLambdaARN,RotationRules:RotationRules,LastRotatedDate:LastRotatedDate}'
undefined
aws secretsmanager describe-secret
--secret-id myapp/production/database
--query '{RotationEnabled:RotationEnabled,RotationLambdaARN:RotationLambdaARN,RotationRules:RotationRules,LastRotatedDate:LastRotatedDate}'
undefined

Lambda Rotation Function

Lambda轮换函数

python
"""rotation_function.py - Custom rotation Lambda for database credentials."""

import boto3
import json
import logging
import psycopg2

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    """Secrets Manager rotation handler.

    The rotation process has four steps:
    1. createSecret - Generate new secret value
    2. setSecret - Apply the new secret to the target service
    3. testSecret - Verify the new secret works
    4. finishSecret - Mark rotation complete
    """
    secret_arn = event['SecretId']
    token = event['ClientRequestToken']
    step = event['Step']

    client = boto3.client('secretsmanager')

    metadata = client.describe_secret(SecretId=secret_arn)
    if not metadata.get('RotationEnabled'):
        raise ValueError(f"Secret {secret_arn} does not have rotation enabled")

    versions = metadata.get('VersionIdsToStages', {})
    if token not in versions:
        raise ValueError(f"Secret version {token} has no stage for rotation")

    if step == "createSecret":
        create_secret(client, secret_arn, token)
    elif step == "setSecret":
        set_secret(client, secret_arn, token)
    elif step == "testSecret":
        test_secret(client, secret_arn, token)
    elif step == "finishSecret":
        finish_secret(client, secret_arn, token)
    else:
        raise ValueError(f"Invalid step: {step}")


def create_secret(client, secret_arn, token):
    """Generate a new secret value."""
    current = client.get_secret_value(
        SecretId=secret_arn, VersionStage="AWSCURRENT"
    )
    current_dict = json.loads(current['SecretString'])

    new_password = client.get_random_password(
        PasswordLength=32,
        ExcludeCharacters='/@"\\',
        RequireEachIncludedType=True,
    )['RandomPassword']

    current_dict['password'] = new_password
    client.put_secret_value(
        SecretId=secret_arn,
        ClientRequestToken=token,
        SecretString=json.dumps(current_dict),
        VersionStages=['AWSPENDING'],
    )
    logger.info(f"createSecret: New secret version created for {secret_arn}")


def set_secret(client, secret_arn, token):
    """Apply the new secret to the target database."""
    pending = client.get_secret_value(
        SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
    )
    pending_dict = json.loads(pending['SecretString'])

    current = client.get_secret_value(
        SecretId=secret_arn, VersionStage="AWSCURRENT"
    )
    current_dict = json.loads(current['SecretString'])

    conn = psycopg2.connect(
        host=current_dict['host'],
        port=current_dict.get('port', 5432),
        user=current_dict['username'],
        password=current_dict['password'],
        dbname=current_dict.get('dbname', 'postgres'),
    )
    conn.autocommit = True
    with conn.cursor() as cur:
        cur.execute(
            "ALTER USER %s WITH PASSWORD %s",
            (pending_dict['username'], pending_dict['password']),
        )
    conn.close()
    logger.info(f"setSecret: Password updated in database for {secret_arn}")


def test_secret(client, secret_arn, token):
    """Verify the new secret works."""
    pending = client.get_secret_value(
        SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
    )
    pending_dict = json.loads(pending['SecretString'])

    conn = psycopg2.connect(
        host=pending_dict['host'],
        port=pending_dict.get('port', 5432),
        user=pending_dict['username'],
        password=pending_dict['password'],
        dbname=pending_dict.get('dbname', 'postgres'),
    )
    conn.close()
    logger.info(f"testSecret: New credentials verified for {secret_arn}")


def finish_secret(client, secret_arn, token):
    """Finalize the rotation by updating version stages."""
    metadata = client.describe_secret(SecretId=secret_arn)
    versions = metadata.get('VersionIdsToStages', {})

    current_version = None
    for version_id, stages in versions.items():
        if "AWSCURRENT" in stages:
            if version_id == token:
                logger.info("finishSecret: Version already marked AWSCURRENT")
                return
            current_version = version_id
            break

    client.update_secret_version_stage(
        SecretId=secret_arn,
        VersionStage="AWSCURRENT",
        MoveToVersionId=token,
        RemoveFromVersionId=current_version,
    )
    logger.info(f"finishSecret: Rotation complete for {secret_arn}")
python
"""rotation_function.py - Custom rotation Lambda for database credentials."""

import boto3
import json
import logging
import psycopg2

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    """Secrets Manager rotation handler.

    The rotation process has four steps:
    1. createSecret - Generate new secret value
    2. setSecret - Apply the new secret to the target service
    3. testSecret - Verify the new secret works
    4. finishSecret - Mark rotation complete
    """
    secret_arn = event['SecretId']
    token = event['ClientRequestToken']
    step = event['Step']

    client = boto3.client('secretsmanager')

    metadata = client.describe_secret(SecretId=secret_arn)
    if not metadata.get('RotationEnabled'):
        raise ValueError(f"Secret {secret_arn} does not have rotation enabled")

    versions = metadata.get('VersionIdsToStages', {})
    if token not in versions:
        raise ValueError(f"Secret version {token} has no stage for rotation")

    if step == "createSecret":
        create_secret(client, secret_arn, token)
    elif step == "setSecret":
        set_secret(client, secret_arn, token)
    elif step == "testSecret":
        test_secret(client, secret_arn, token)
    elif step == "finishSecret":
        finish_secret(client, secret_arn, token)
    else:
        raise ValueError(f"Invalid step: {step}")


def create_secret(client, secret_arn, token):
    """Generate a new secret value."""
    current = client.get_secret_value(
        SecretId=secret_arn, VersionStage="AWSCURRENT"
    )
    current_dict = json.loads(current['SecretString'])

    new_password = client.get_random_password(
        PasswordLength=32,
        ExcludeCharacters='/@"\\',
        RequireEachIncludedType=True,
    )['RandomPassword']

    current_dict['password'] = new_password
    client.put_secret_value(
        SecretId=secret_arn,
        ClientRequestToken=token,
        SecretString=json.dumps(current_dict),
        VersionStages=['AWSPENDING'],
    )
    logger.info(f"createSecret: New secret version created for {secret_arn}")


def set_secret(client, secret_arn, token):
    """Apply the new secret to the target database."""
    pending = client.get_secret_value(
        SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
    )
    pending_dict = json.loads(pending['SecretString'])

    current = client.get_secret_value(
        SecretId=secret_arn, VersionStage="AWSCURRENT"
    )
    current_dict = json.loads(current['SecretString'])

    conn = psycopg2.connect(
        host=current_dict['host'],
        port=current_dict.get('port', 5432),
        user=current_dict['username'],
        password=current_dict['password'],
        dbname=current_dict.get('dbname', 'postgres'),
    )
    conn.autocommit = True
    with conn.cursor() as cur:
        cur.execute(
            "ALTER USER %s WITH PASSWORD %s",
            (pending_dict['username'], pending_dict['password']),
        )
    conn.close()
    logger.info(f"setSecret: Password updated in database for {secret_arn}")


def test_secret(client, secret_arn, token):
    """Verify the new secret works."""
    pending = client.get_secret_value(
        SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
    )
    pending_dict = json.loads(pending['SecretString'])

    conn = psycopg2.connect(
        host=pending_dict['host'],
        port=pending_dict.get('port', 5432),
        user=pending_dict['username'],
        password=pending_dict['password'],
        dbname=pending_dict.get('dbname', 'postgres'),
    )
    conn.close()
    logger.info(f"testSecret: New credentials verified for {secret_arn}")


def finish_secret(client, secret_arn, token):
    """Finalize the rotation by updating version stages."""
    metadata = client.describe_secret(SecretId=secret_arn)
    versions = metadata.get('VersionIdsToStages', {})

    current_version = None
    for version_id, stages in versions.items():
        if "AWSCURRENT" in stages:
            if version_id == token:
                logger.info("finishSecret: Version already marked AWSCURRENT")
                return
            current_version = version_id
            break

    client.update_secret_version_stage(
        SecretId=secret_arn,
        VersionStage="AWSCURRENT",
        MoveToVersionId=token,
        RemoveFromVersionId=current_version,
    )
    logger.info(f"finishSecret: Rotation complete for {secret_arn}")

Rotation Lambda Terraform

轮换Lambda的Terraform配置

hcl
resource "aws_lambda_function" "rotation" {
  filename         = "rotation_function.zip"
  function_name    = "secrets-rotation-postgresql"
  role             = aws_iam_role.rotation.arn
  handler          = "rotation_function.lambda_handler"
  runtime          = "python3.11"
  timeout          = 60

  vpc_config {
    subnet_ids         = var.private_subnet_ids
    security_group_ids = [aws_security_group.rotation.id]
  }

  environment {
    variables = {
      SECRETS_MANAGER_ENDPOINT = "https://secretsmanager.${var.region}.amazonaws.com"
    }
  }
}

resource "aws_lambda_permission" "secrets_manager" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.rotation.function_name
  principal     = "secretsmanager.amazonaws.com"
  statement_id  = "AllowSecretsManager"
}

resource "aws_secretsmanager_secret_rotation" "db" {
  secret_id           = aws_secretsmanager_secret.db.id
  rotation_lambda_arn = aws_lambda_function.rotation.arn
  rotation_rules {
    automatically_after_days = 30
  }
}
hcl
resource "aws_lambda_function" "rotation" {
  filename         = "rotation_function.zip"
  function_name    = "secrets-rotation-postgresql"
  role             = aws_iam_role.rotation.arn
  handler          = "rotation_function.lambda_handler"
  runtime          = "python3.11"
  timeout          = 60

  vpc_config {
    subnet_ids         = var.private_subnet_ids
    security_group_ids = [aws_security_group.rotation.id]
  }

  environment {
    variables = {
      SECRETS_MANAGER_ENDPOINT = "https://secretsmanager.${var.region}.amazonaws.com"
    }
  }
}

resource "aws_lambda_permission" "secrets_manager" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.rotation.function_name
  principal     = "secretsmanager.amazonaws.com"
  statement_id  = "AllowSecretsManager"
}

resource "aws_secretsmanager_secret_rotation" "db" {
  secret_id           = aws_secretsmanager_secret.db.id
  rotation_lambda_arn = aws_lambda_function.rotation.arn
  rotation_rules {
    automatically_after_days = 30
  }
}

Application Integration

应用集成

Python SDK

Python SDK示例

python
import boto3
import json
from functools import lru_cache

def get_secret(secret_name: str, region: str = "us-east-1") -> dict:
    """Retrieve and parse a secret from AWS Secrets Manager."""
    client = boto3.client("secretsmanager", region_name=region)
    response = client.get_secret_value(SecretId=secret_name)
    if "SecretString" in response:
        return json.loads(response["SecretString"])
    else:
        import base64
        return base64.b64decode(response["SecretBinary"])

@lru_cache(maxsize=32)
def get_cached_secret(secret_name: str) -> dict:
    """Cached secret retrieval. Clear cache on rotation events."""
    return get_secret(secret_name)
python
import boto3
import json
from functools import lru_cache

def get_secret(secret_name: str, region: str = "us-east-1") -> dict:
    """Retrieve and parse a secret from AWS Secrets Manager."""
    client = boto3.client("secretsmanager", region_name=region)
    response = client.get_secret_value(SecretId=secret_name)
    if "SecretString" in response:
        return json.loads(response["SecretString"])
    else:
        import base64
        return base64.b64decode(response["SecretBinary"])

@lru_cache(maxsize=32)
def get_cached_secret(secret_name: str) -> dict:
    """Cached secret retrieval. Clear cache on rotation events."""
    return get_secret(secret_name)

Usage

使用示例

creds = get_secret("myapp/production/database") connection_string = ( f"postgresql://{creds['username']}:{creds['password']}" f"@{creds['host']}:{creds['port']}/{creds['dbname']}" )
undefined
creds = get_secret("myapp/production/database") connection_string = ( f"postgresql://{creds['username']}:{creds['password']}" f"@{creds['host']}:{creds['port']}/{creds['dbname']}" )
undefined

ECS Task Definition

ECS任务定义

json
{
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "ghcr.io/acme/myapp:v1.0.0",
      "secrets": [
        {
          "name": "DB_USERNAME",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:username::"
        },
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:password::"
        },
        {
          "name": "API_KEY",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/api-key"
        }
      ]
    }
  ],
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole"
}
json
{
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "ghcr.io/acme/myapp:v1.0.0",
      "secrets": [
        {
          "name": "DB_USERNAME",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:username::"
        },
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:password::"
        },
        {
          "name": "API_KEY",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/api-key"
        }
      ]
    }
  ],
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole"
}

EKS with External Secrets Operator

EKS与External Secrets Operator集成

yaml
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: username
      remoteRef:
        key: myapp/production/database
        property: username
    - secretKey: password
      remoteRef:
        key: myapp/production/database
        property: password
yaml
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: username
      remoteRef:
        key: myapp/production/database
        property: username
    - secretKey: password
      remoteRef:
        key: myapp/production/database
        property: password

Resource-Based Policy

基于资源的策略

bash
undefined
bash
undefined

Restrict secret access to specific roles

限制特定角色访问密钥

aws secretsmanager put-resource-policy
--secret-id myapp/production/database
--resource-policy '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::123456789:role/myapp-ecs-task-role", "arn:aws:iam::123456789:role/myapp-lambda-role" ] }, "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "", "Condition": { "StringEquals": { "aws:RequestedRegion": "us-east-1" } } }, { "Effect": "Deny", "Principal": "", "Action": "secretsmanager:GetSecretValue", "Resource": "*", "Condition": { "StringNotEquals": { "aws:PrincipalAccount": "123456789012" } } } ] }'
undefined
aws secretsmanager put-resource-policy
--secret-id myapp/production/database
--resource-policy '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::123456789:role/myapp-ecs-task-role", "arn:aws:iam::123456789:role/myapp-lambda-role" ] }, "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "", "Condition": { "StringEquals": { "aws:RequestedRegion": "us-east-1" } } }, { "Effect": "Deny", "Principal": "", "Action": "secretsmanager:GetSecretValue", "Resource": "*", "Condition": { "StringNotEquals": { "aws:PrincipalAccount": "123456789012" } } } ] }'
undefined

Troubleshooting

故障排查

ProblemCauseSolution
AccessDeniedException
on GetSecretValue
IAM policy missing permissionAdd
secretsmanager:GetSecretValue
to the role; check resource-based policy
Rotation fails with Lambda timeoutLambda cannot reach databaseEnsure Lambda is in same VPC with route to DB; check security groups
Secret value is empty after rotationcreateSecret step failedCheck Lambda CloudWatch logs; verify random password generation works
ECS container fails to startSecret ARN format incorrectUse full ARN with
::
for JSON key extraction; verify secret exists
Application uses old credentials after rotationClient caching stale valuesImplement cache invalidation on rotation; reduce cache TTL
Rotation Lambda permission errorMissing
lambda:InvokeFunction
permission
Add
aws_lambda_permission
for secretsmanager.amazonaws.com principal
KMS decrypt failsSecret KMS key policy missing roleAdd the accessing role to the KMS key policy's
kms:Decrypt
principals
问题原因解决方案
调用GetSecretValue时出现
AccessDeniedException
IAM策略缺少权限为角色添加
secretsmanager:GetSecretValue
权限;检查基于资源的策略
轮换因Lambda超时失败Lambda无法连接数据库确保Lambda与数据库在同一VPC且有路由;检查安全组配置
轮换后密钥值为空createSecret步骤执行失败查看Lambda CloudWatch日志;验证随机密码生成功能正常
ECS容器启动失败密钥ARN格式错误使用包含
::
的完整ARN提取JSON字段;验证密钥存在
轮换后应用仍使用旧凭证客户端缓存了过期值实现轮换时的缓存失效机制;缩短缓存TTL
轮换Lambda出现权限错误缺少
lambda:InvokeFunction
权限
为secretsmanager.amazonaws.com主体添加
aws_lambda_permission
KMS解密失败密钥KMS密钥策略缺少角色将访问角色添加到KMS密钥策略的
kms:Decrypt
主体列表中

Best Practices

最佳实践

  • Enable automatic rotation with 30-day intervals minimum
  • Use resource-based policies in addition to IAM policies (defense in depth)
  • Encrypt secrets with customer-managed KMS keys (not default)
  • Implement least-privilege access (only the roles that need each secret)
  • Use secret versioning for safe rollback during rotation issues
  • Monitor secret access with CloudTrail and alert on unusual patterns
  • Structure secret names hierarchically:
    {app}/{env}/{secret-type}
  • Never log secret values; log only secret ARNs and access metadata
  • Test rotation in staging before enabling in production
  • Set up CloudWatch alarms for rotation failures
  • 启用自动轮换,最小间隔为30天
  • 除IAM策略外,同时使用基于资源的策略(深度防御)
  • 使用客户管理的KMS密钥加密密钥(而非默认密钥)
  • 实现最小权限访问(仅为需要的角色分配密钥权限)
  • 使用密钥版本控制,以便在轮换出现问题时安全回滚
  • 通过CloudTrail监控密钥访问,并对异常模式发出警报
  • 按层级结构命名密钥:
    {应用}/{环境}/{密钥类型}
  • 切勿记录密钥值;仅记录密钥ARN和访问元数据
  • 在生产环境启用轮换前,先在预发布环境测试
  • 为轮换失败设置CloudWatch告警

Related Skills

相关技能

  • hashicorp-vault - Multi-cloud secrets
  • aws-iam - IAM policies
  • azure-keyvault - Azure secret management
  • gcp-secret-manager - GCP secret management
  • hashicorp-vault - 多云密钥管理
  • aws-iam - IAM策略配置
  • azure-keyvault - Azure密钥管理
  • gcp-secret-manager - GCP密钥管理