为什么我的 Secrets Manager Lambda 轮换失败?
我配置了 AWS Lambda 轮换函数,以便使用代入角色来轮换我的 AWS Secrets Manager 密钥或在 AWS 账户之间轮换。但该函数没有轮换密钥。
简短描述
2024 年 12 月,对于在轮换过程中调用 PutSecretValue API 操作的实体,Secrets Manager 更改了对该实体进行验证的方式。此更改会影响跨账户轮换和代入角色轮换。
该函数必须传递轮换令牌,这样 Secrets Manager 才能验证实体的身份。然后,Lambda 轮换函数可以调用 PutSecretValue。
如果您在 2024 年 12 月之前没有更新轮换函数代码,那么妥善的做法是更新代码。检查 AWS CloudTrail 中是否有 RotationFailed 事件,且包含消息:“Pending secret version VERSION_ID for Secret SECRET_ARN wasn't created by Lambda LAMBDA_ARN.Remove the AWSPENDING staging label and restart rotation”(密钥 SECRET_ARN 的待处理密钥版本 VERSION_ID 不是由 Lambda LAMBDA_ARN 创建。移除 AWSENDING 暂存标签并重新开始轮换)。如果找到 RotationFailed 事件,则更新 Lambda 函数以使用 RotationToken 参数。
**注意:**如果不使用跨账户轮换或代入角色,则无需进行任何更改。
解决方法
下载 Lambda 函数代码
完成以下步骤:
- 打开 Lambda 控制台。
- 在导航窗格中,选择 Functions(函数)。
- 在 Function name(函数名称)中,选择用于轮换密钥的 Lambda 函数。
- 在 Download(下载)中,选择以下选项之一:
Function code .zip(函数代码 .zip)
AWS SAM file(AWS SAM 文件)
Both(两者) - 选择 OK(确定)将函数保存在本地计算机上。
编辑 Lambda 函数代码
打开您的代码编辑器,然后编辑 Lambda 函数代码。以下示例展示了您可能需要进行的代码编辑。
编辑 lambda_handler 代码
在跨账户轮换的 create_secret 步骤中包括 rotation_token 参数:
def lambda_handler(event, context): """Secrets Manager Rotation Template This is a template for creating an AWS Secrets Manager rotation lambda Args: event (dict): Lambda dictionary of event parameters. These keys must include the following: - SecretId: The secret ARN or identifier - ClientRequestToken: The ClientRequestToken of the secret version - Step: The rotation step (one of createSecret, setSecret, testSecret, or finishSecret) - RotationToken: the rotation token to put as parameter for PutSecretValue call context (LambdaContext): The Lambda runtime information Raises: ResourceNotFoundException: If the secret with the specified arn and stage does not exist ValueError: If the secret is not properly configured for rotation KeyError: If the event parameters do not contain the expected keys """ arn = event['SecretId'] token = event['ClientRequestToken'] step = event['Step'] # Add the rotation token rotation_token = event['RotationToken'] # Setup the client service_client = boto3.client('secretsmanager', endpoint_url=os.environ['SECRETS_MANAGER_ENDPOINT']) # Make sure the version is staged correctly metadata = service_client.describe_secret(SecretId=arn) if not metadata['RotationEnabled']: logger.error("Secret %s is not enabled for rotation" % arn) raise ValueError("Secret %s is not enabled for rotation" % arn) versions = metadata['VersionIdsToStages'] if token not in versions: logger.error("Secret version %s has no stage for rotation of secret %s." % (token, arn)) raise ValueError("Secret version %s has no stage for rotation of secret %s." % (token, arn)) if "AWSCURRENT" in versions[token]: logger.info("Secret version %s already set as AWSCURRENT for secret %s." % (token, arn)) return elif "AWSPENDING" not in versions[token]: logger.error("Secret version %s not set as AWSPENDING for rotation of secret %s." % (token, arn)) raise ValueError("Secret version %s not set as AWSPENDING for rotation of secret %s." % (token, arn)) # Use rotation_token if step == "createSecret": create_secret(service_client, arn, token, rotation_token) elif step == "setSecret": set_secret(service_client, arn, token) elif step == "testSecret": test_secret(service_client, arn, token) elif step == "finishSecret": finish_secret(service_client, arn, token) else: raise ValueError("Invalid step parameter")
编辑 create_secret 代码
更新 create_secret 函数以接受和使用 rotation_token 参数:
# Add rotation_token to the function def create_secret(service_client, arn, token, rotation_token): """Create the secret This method first checks for the existence of a secret for the passed in token. If one does not exist, it will generate a new secret and put it with the passed in token. Args: service_client (client): The secrets manager service client arn (string): The secret ARN or other identifier token (string): The ClientRequestToken associated with the secret version rotation_token (string): the rotation token to put as parameter for PutSecretValue call Raises: ResourceNotFoundException: If the secret with the specified arn and stage does not exist """ # Make sure the current secret exists service_client.get_secret_value(SecretId=arn, VersionStage="AWSCURRENT") # Now try to get the secret version, if that fails, put a new secret try: service_client.get_secret_value(SecretId=arn, VersionId=token, VersionStage="AWSPENDING") logger.info("createSecret: Successfully retrieved secret for %s." % arn) except service_client.exceptions.ResourceNotFoundException: # Get exclude characters from environment variable exclude_characters = os.environ['EXCLUDE_CHARACTERS'] if 'EXCLUDE_CHARACTERS' in os.environ else '/@"\'\\' # Generate a random password passwd = service_client.get_random_password(ExcludeCharacters=exclude_characters) # Put the secret, using rotation_token service_client.put_secret_value(SecretId=arn, ClientRequestToken=token, SecretString=passwd['RandomPassword'], VersionStages=['AWSPENDING'], RotationToken=rotation_token) logger.info("createSecret: Successfully put secret for ARN %s and version %s." % (arn, token))
上传更新后的 Lambda 函数代码
更新 Lambda 函数代码后,上传代码以轮换您的密钥。
相关信息
我的 Lambda 轮换函数调用了第二个函数来轮换 Secrets Manager 密钥,但失败了。为什么第二个 Lambda 函数失败了?
- 语言
- 中文 (简体)
