Question
I am using serverless.env.yml file which defines all of the env properties. Many of these env properties are being read/resolved from the secret manager directly at the time CloudFormation runs (see the env.yml file below). Example
securityGroupIds:
- "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_vpc_securityGroupIds}}"
We have it working correctly for all of the properties.
Just recently I am also trying to move the lambda execution role name into a secret variable like this
lambdaRole: "{{resolve:secretsmanager:${self:provider.deployVersion}_cph_cloudwatch_vpc}}"
I am getting a template error when doing serverless deploy. If I change the value to below it works
lambdaRole: arn:aws:iam::#{AWS::AccountId}:role/V1-CPH-Cloudwatch-VPC
I believe lambda execution roles cannot be resolved from secrets and this has something to do with how Serverless generates the templates. In the case where it works the template has the role correctly set
"Role": { "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/V1-CPH-Cloudwatch-VPC" },
where as in the case where I resolve the role from secret the template looks like this. I believe this is what fails in AWS CloudFormation as it is using a GetAtt instead of a sub or resolve
"Role": {
"Fn::GetAtt": [
"{{resolve:secretsmanager:v1_cph_cloudwatch_vpc}}",
"Arn"
]
},
From further research I can confirm that this may be tied to how Serverless’s template generation because I manually modified the role set in Serverless generated template as below and then the functions could deploy.
"Role": "{{resolve:secretsmanager:v1_cph_cloudwatch_vpc}}",
Any idea if this will be supported or if I am missing anything? maybe there is a plugin I can use for this.
Command Run
sls deploy --service <serviceName> --stage qa --env deploy
Console Output
{{Serverless: Validating template…
Error --------------------------------------------------
Error: The CloudFormation template is invalid: Template error: instance of Fn::GetAtt references undefined resource {
{resolve:secretsmanager:v1_cph_cloudwatch_vpc}
}
at provider.request.catch.error (C:<local_directory>\npm\node_modules\serverless\lib\plugins\aws\deploy\lib\validateTemplate.js:20:13)
at tryCatcher (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:547:31)
at Promise._settlePromise (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:725:18)
at _drainQueueStep (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:93:12)
at _drainQueue (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:86:9)
at Async._drainQueues (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:102:5)
at Immediate.Async.drainQueues [as _onImmediate] (C:<local_directory>\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:15:14)
at runCallback (timers.js:696:18)
at tryOnImmediate (timers.js:667:5)
at processImmediate (timers.js:649:5)
at process.topLevelDomainCallback (domain.js:121:23)}}
Serverless.yml
service: ${self:provider.deployVersion}-cph-${opt:service}
provider:
name: aws
endpointType: ${opt:endpoint, 'regional'}
runtime: nodejs12.x
region: us-east-1
memorySize: 128
timeout: 25
deployVersion: v1
versionFunctions: false
**_role: ${self:custom.env.lambdaRole}_**
deploymentBucket: ${opt:deploymentBucket, '${ssm:/aws/reference/secretsmanager/${self:provider.deployVersion}_deployment_S3Bucket~true}'}
vpc: ${self:custom.env.vpc}
stage: ${opt:stage, 'dev'}
accessControlAllowOrigin: ${self:custom.env.accessControlAllowOrigin}
stackTags:
buildTag: ${opt:buildTag, ' '}
releaseVersion: ${opt:releaseVersion, ' '}
environment:
stage: ${self:provider.stage}
region: ${self:provider.region}
cognitoPoolRegion: ${self:provider.region}
rdsConnectionDialect: ${self:custom.env.rdsConnectionDialect}
rdsConnectionHost: ${self:custom.env.rdsConnectionHost}
rdsConnectionDatabase: ${self:custom.env.rdsConnectionDatabase}
rdsConnectionUsername: ${self:custom.env.rdsConnectionUsername}
rdsConnectionPassword: ${self:custom.env.rdsConnectionPassword}
plugins:
- serverless-plugin-typescript
- serverless-offline
- serverless-reqvalidator-plugin
- cph-serverless-aws-models
- serverless-pseudo-parameters
- serverless-plugin-bind-deployment-id
functions:
- ${file(./serverless/${opt:service}.yml):functions}
resources:
- ${file(./serverless/basePathMapping.yml)}
- ${file(./serverless/apiGatewayErrorResponses.yml)}
- ${file(./serverless/apiGatewayValidators.yml)}
- ${file(./serverless/outputs.yml)}
custom:
env: ${file(./serverless.env.yml):${opt:env, 'deploy'}}
webpackIncludeModules: true;
webpack:
includeModules:
forceInclude:
- pg
- sequelize
- sequelize-typescript
apigwBinary:
types:
- "multipart/form-data"
- "application/pdf"
- "image/*"
models: ${file(./serverless/${opt:service}.yml):custom.models}
serverless.env.yml
deploy:
rdsConnectionDialect: postgres
_**lambdaRole: "{{resolve:secretsmanager:${self:provider.deployVersion}_cph_cloudwatch_vpc}}"**_
lambdaAuthorizerARN: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:provider.deployVersion}-cph-RequestAuthorizer-${self:provider.stage}-authorizerFunc
domain: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_domainName}}"
rdsConnectionHost: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_databaseHost}}"
rdsConnectionDatabase: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_databaseName}}"
rdsConnectionUsername: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_databaseUserName}}"
rdsConnectionPassword: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_databasePassword}}"
accessControlAllowOrigin: "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_accessControlAllowOrigin}}"
vpc:
securityGroupIds:
- "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_vpc_securityGroupIds}}"
subnetIds:
- "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_vpc_subnetIds_1}}"
- "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_vpc_subnetIds_2}}"
- "{{resolve:secretsmanager:${self:provider.deployVersion}_${self:provider.stage}_vpc_subnetIds_3}}"
Environment Information ---------------------------
Operating System: win32
Node Version: 10.6.0
Framework Version: 1.56.1
Plugin Version: 3.2.1
SDK Version: 2.2.0
Components Core Version: 1.1.2
Components CLI Version: 1.4.0