为何Lambda Skill CDK构造不接受传入的cdk.SecretValue参数?
问题:AWS CDK部署栈时触发SecretValue暴露风险错误
错误信息
Resolution error: Synthing a secret value to . Using a SecretValue here risks exposing your secret. Only pass SecretValues to constructs that accept a SecretValue property, or call AWS Secrets Manager directly in your runtime code. Call 'secretValue.unsafeUnwrap()' if you understand and accept the risks..
调用栈:
Object creation stack: at new Intrinsic (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/aws-cdk-lib/core/lib/private/intrinsic.js:1:680) at new SecretValue (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/aws-cdk-lib/core/lib/secret-value.js:1:592) at Function.cfnDynamicReference (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/aws-cdk-lib/core/lib/secret-value.js:1:2713) at Function.secretsManager (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/aws-cdk-lib/core/lib/secret-value.js:1:2202) at HltbStack.retrieveSecrets (/Users/john/Desktop/Production/alexa skills/hltb/lib/hltb-stack.ts:55:45) at new HltbStack (/Users/john/Desktop/Production/alexa skills/hltb/lib/hltb-stack.ts:27:12) at Object.<anonymous> (/Users/john/Desktop/Production/alexa skills/hltb/bin/hltb.ts:20:1) at Module._compile (internal/modules/cjs/loader.js:1085:14) at Module.m._compile (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/index.ts:1618:23) at Module._extensions..js (internal/modules/cjs/loader.js:1114:10) at Object.require.extensions.<computed> [as .ts] (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/index.ts:1621:12) at Module.load (internal/modules/cjs/loader.js:950:32) at Function.Module._load (internal/modules/cjs/loader.js:790:12) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12) at phase4 (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/bin.ts:649:14) at bootstrap (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/bin.ts:95:10) at main (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/bin.ts:55:10) at Object.<anonymous> (/Users/john/Desktop/Production/alexa skills/hltb/node_modules/ts-node/src/bin.ts:800:3) at Module._compile (internal/modules/cjs/loader.js:1085:14) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10) at Module.load (internal/modules/cjs/loader.js:950:32) at Function.Module._load (internal/modules/cjs/loader.js:790:12) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12) at /Users/john/.nvm/versions/node/v14.20.1/lib/node_modules/npm/node_modules/libnpx/index.js:268:14
栈代码
import { Stack } from "aws-cdk-lib"; import * as cdk from "aws-cdk-lib"; import * as lambda from "aws-cdk-lib/aws-lambda"; import { Skill } from "cdk-alexa-skill"; import * as path from "path"; import { Props } from "../bin/hltb"; import * as ssm from "aws-cdk-lib/aws-ssm"; export type SkillConfig = { alexaVendorIdSecretValue: string; lwaClientIdSecretValue: string; lwaClientSecretSecretValue: string; lwaRefreshTokenSecretValue: string; }; export class HltbStack extends Stack { constructor(scope: cdk.App, id: string, props: Props) { super(scope, id, props); const skillBackendLambdaFunction = new lambda.Function(this, "Function", { runtime: lambda.Runtime.NODEJS_16_X, handler: "handler.handler", code: lambda.Code.fromAsset(path.join(__dirname, "/../src/handlers")), }); const { alexaVendorId, lwaClientId, lwaClientSecret, lwaRefreshToken } = this.retrieveSecrets(props); const skill = new Skill(this, "hltbSkill", { endpointLambdaFunction: skillBackendLambdaFunction, skillPackagePath: "src/skill-package", alexaVendorId, lwaClientId, lwaClientSecret, lwaRefreshToken, }); } private retrieveSecrets(props: Props): { alexaVendorId: string; lwaClientId: string; lwaClientSecret: cdk.SecretValue; lwaRefreshToken: cdk.SecretValue; } { const alexaVendorId = ssm.StringParameter.valueForStringParameter( this, props.alexaVendorIdSecretValue ); const lwaClientId = ssm.StringParameter.valueForStringParameter( this, props.lwaClientIdSecretValue ); const lwaClientSecret = cdk.SecretValue.secretsManager( props.lwaClientSecretSecretValue ); const lwaRefreshToken = cdk.SecretValue.secretsManager( props.lwaRefreshTokenSecretValue ); return { alexaVendorId, lwaClientId, lwaClientSecret, lwaRefreshToken, }; } }
Skill组件类型定义
export interface SkillProps { readonly endpointLambdaFunction?: lambda.IFunction; readonly skillPackagePath: string; readonly alexaVendorId: string; readonly lwaClientId: string; readonly lwaClientSecret: cdk.SecretValue; readonly lwaRefreshToken: cdk.SecretValue; }
问题分析与解决方案
原因
尽管你按照SkillProps定义传入了cdk.SecretValue类型的值,但cdk-alexa-skill库的内部实现可能将这些SecretValue转换为字符串(比如构造Alexa API请求参数),触发了CDK的安全检测——CDK禁止直接将SecretValue转为字符串,避免秘密值在CloudFormation模板或部署日志中暴露。
解决方案
由于cdk-alexa-skill在部署阶段需要直接使用凭证调用Alexa管理API,无法通过CloudFormation动态引用传递,因此需要明确调用unsafeUnwrap()告知CDK你已了解风险并接受:
- 修改
retrieveSecrets方法中获取秘密值的代码:
const lwaClientSecret = cdk.SecretValue.secretsManager( props.lwaClientSecretSecretValue ).unsafeUnwrap(); const lwaRefreshToken = cdk.SecretValue.secretsManager( props.lwaRefreshTokenSecretValue ).unsafeUnwrap();
- 同步修改
retrieveSecrets的返回类型,将两个秘密字段改为string:
private retrieveSecrets(props: Props): { alexaVendorId: string; lwaClientId: string; lwaClientSecret: string; lwaRefreshToken: string; }
- 若
SkillProps严格要求SecretValue类型,需检查cdk-alexa-skill库是否有版本更新修复该兼容性问题。
内容的提问来源于stack exchange,提问作者John Nezzi
相关产品推荐
相关产品推荐

