Use SSM parameter whose name depends on a CFN parameter - amazon-web-services

I have a CloudFormation template that looks something like the following:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
env:
Type: String
Default: NONE
Resources:
GraphQLAPI:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub 'my-api-${env}'
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: <something>
AwsRegion: !Ref AWS::Region
DefaultAction: ALLOW
Suppose that I already have a SSM parameter named /dev/cognitoUserPoolId. When I create this template, passing env=dev, I want to use the value of that parameter as the UserPoolId. I want to avoid manually passing a new CFN parameter for every SSM parameter, as there may be quite a few in practice.

You should be able to use dynamic references to the SSM parameters in your template.
Something like:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
env:
Type: String
Default: NONE
Resources:
GraphQLAPI:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub 'my-api-${env}'
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Sub '{{resolve:ssm:/${env}/cognitoUserPoolId:1}}'
AwsRegion: !Ref AWS::Region
DefaultAction: ALLOW
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html

Related

Reference Secrets Manager Parameters to Secret String

Is there any way to reference parameters in SecretString field in Secrets Manager via CloudFormation?
The way I made the script, the !Ref parameter is a text and not a reference to the parameter.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Name:
Type: String
myuserparameter:
Type: String
mypasswordparameter:
Type: String
Resources:
SecretsManager:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Ref Name
SecretString: '{"username":"!Ref myuserparameter,"password":"Ref mypasswordparameter"}'
this will work:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Name:
Type: String
myuserparameter:
Type: String
mypasswordparameter:
Type: String
Resources:
SecretsManager:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Ref Name
SecretString: !Sub '{"username": "${myuserparameter}","password": "${mypasswordparameter}"}'

Cloudformation ImportValue within ParameterOverride CodePipeline

Problem:
I have a cloudformation template that is supposed to retrieve code found in CodeCommit and push it to a Lambda. The code in CodeCommit also contains a SAM template with a few parameters. The SAM template has the following setup
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Deploy Python code to Lambda
Parameters:
ArtifactsBucket:
Description: The artifact bucket to get the lambda code
Type: String
Name:
Description: Name of the lambda function
Type: String
SqsARN:
Description: AWS SQS Arn to act as a trigger for the lambda function
Type: String
...
and the CodePipeline Cloudformation template has the following to override the 3 parameters present in the SAM template.
...
- Name: Deploy
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
Capabilities: 'CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND,CAPABILITY_NAMED_IAM'
ChangeSetName: !Join
- '-'
- - lambda
- !Ref CodeCommitRepoName
ParameterOverrides: !Sub |
{
"ArtifactsBucket": "${ArtifactsBucket}",
"Name": "${CodeCommitRepoName}",
"SqsARN": {"Fn::ImportValue": "My-queue:us-east-1:Queue:Arn"}
}
...
The ArtifactBucket and the Name parameters are easily changed by the !Sub function but I am not able to have a valid value for SqsARN which is an imported value.
QuestionIs there anyway to include ImportValue in conjungtion with a Sub function within ParametersOverride?
Attempts I also tried to switch from
{"Fn::ImportValue": "My-queue:us-east-1:Queue:Arn"}
to
!ImportValue": "My-queue:us-east-1:Queue:Arn"
which also did not work. Remove the !Sub function and using a !Ref function yields the same output/problem as with ImportValue.
Key thing to remember is, using JSON within YAML
From the documentation
You can't use the short form of !ImportValue when it contains a !Sub.
It is valid for AWS CloudFormation, but not valid
for YAML:
Assuming Environment as Parameter, Here is a working example of Sub >> ImportValue >> Sub
Value: !Sub
- '{
"sqsUrl": "${sqsUrl}",
}'
- {
sqsUrl: { 'Fn::ImportValue': { 'Fn::Sub': 'QueUrl-${Environment}' } }
}
Applying it to above example might look something like below(using ssm for testing)
Parameters:
Environment:
Type: String
Default: DV
ArtifactsBucket:
Type: String
Default: TestBucket
CodeCommitRepoName:
Type: String
Default: Test
Resources:
SmsLambdaParameter:
Type: 'AWS::SSM::Parameter'
Properties:
Name: !Sub
- '/${EnvFullUpper}/My-Param/Test'
- { EnvFullUpper: !Ref Environment }
Type: 'String'
Value: !Sub
- '{
"ArtifactsBucket": "${ArtifactsBucket}",
"Name": "${CodeCommitRepoName}",
"SqsARN": "${SqsArn}"
}'
- { SqsARN: { 'Fn::ImportValue': { 'Fn::Sub': 'QueueArn-${Environment}' } } }
You can use array form of Fn::Sub:
!Sub
- String
- Var1Name: Var1Value
Var2Name: Var2Value
which would result in:
ParameterOverrides: !Sub
- |
{
"ArtifactsBucket": "${ArtifactsBucket}",
"Name": "${CodeCommitRepoName}",
"SqsARN": "${SqsARNImport}"
}
- SqsARNImport: !ImportValue <name-of-your-queue-export>

Passing values from parent stack to nested stack for Cloudformation

I am new to nested stack and i am trying to pass input parameters from parent to child template. My parent stack looks like below:
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::Serverless-2016-10-31'
Description: "ParentStack with all child stack"
Parameters:
AccountName:
Description: Please Enter valid Account Name.
Type: "CommaDelimitedList"
Default: "citi"
Region:
Description: Enter Region
Type: "CommaDelimitedList"
Default: "us-east-2"
S3BucketName:
Type: "CommaDelimitedList"
Default: ""
S3KeyName:
Type: "CommaDelimitedList"
Default: "Test-LambdaFunction.zip"
Resources:
LambdaStack1:
Type: "AWS::CloudFormation::Stack"
Properties:
Parameters:
TemplateURL: https://test272t3.s3.us-east-2.amazonaws.com/CFTemplates/lambda.yaml
CodeUri:
Bucket: Fn:Join [ ' ', [!Ref S3BucketName] ]
Key: Fn::Join [ ' ', [!Ref S3KeyName] ]
S3Stack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://test272t3.s3.us-east-2.amazonaws.com/CFTemplates/s3child.yaml
Parameters:
BucketName: <<not sure how !sub can be paased in parent stack>>
AccessControl: PublicReadWrite
VersioningConfiguration:
Status: Suspended
And part of child template is as follows:
Parameters:
AccountName:
Description: Please Enter valid Account Name.
Type: String
Default: citi
Region:
Description: Enter Region
Type: String
Default: us-east-2
S3BucketName:
Type: "String"
Default: ""
S3KeyName:
Type: "String"
Default: "MeghFlow-DBConnMgmt-Lambda-DBConnMgmtFunction.zip"
testLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri:
Bucket: !Ref S3BucketName
Key: !Ref S3KeyName
Handler: com.testff.testinghand.dbconnmgmt.lambda.testLambda::handleRequest
Runtime: java8
MemorySize: 1024
Policies: AmazonDynamoDBFullAccess
Environment:
Variables:
REGION: us-east-2
DYNAMODB_NAME: DBConnectionInfo
ArtifactBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub ${AccountName}-${Region}-artifacts
AccessControl: PublicReadWrite
VersioningConfiguration:
Status: Suspended
Issue: I am not quite sure how the input parameters can be passed from parent to child. I referred few links like but i was confused even more as to when the input type must be CommaDelimitedList vs string. I even tried keeping the param type to string in both parent and child but still i get below error:
"Value of property Parameters must be an object with String (or simple type) properties"
and on using Fn::join get error as below:
"Fn::Join object requires two parameters, (1) a string delimiter and (2) a list of strings to be joined or a function that returns a list of strings (such as Fn::GetAZs) to be joined."
Have referred link : Trying to pass parameters from Master to child template but no luck .
Can anyone guide me in correct direction please. Thanks in advance.
Thanks #gandaliter for your guidance. As per above marked answer CloudFormation parent stack accepts only strings and not any object level parameters(sub parameters under parameters just like CodeURI in my above code). I did few tweaks and changed all the parent template to below :
Note: All the parameter type are set to String in child and parent template
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::Serverless-2016-10-31'
Description: "ParentStack with all child stack"
Parameters:
apiGatewayStageName:
Type: String
Default: "dev"
HandlerName:
Type: String
Default: "com.test.tehgsaLambda::handleRequest"
S3BucketName:
Type: String
Default: ""
S3KeyName:
Type: String
Default: "Test-LambdaFunction.zip"
Resources:
LambdaStack1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL:
Fn::Sub: "https://testyu2y73.s3.us-east-2.amazonaws.com/CFTemplates/lambda.yaml"
Parameters:
S3BucketName: !Ref S3BucketName
S3KeyName: !Ref S3KeyName
HandlerName: !Ref HandlerName
apiGatewayStageName: !Ref apiGatewayStageName
```
I imagine the code you've given above isn't the only combination you've tried, and the parameters don't exactly line up between your parent and child stack, but in any case, the problem is that you're trying to give parameter values of:
CodeUri:
Bucket: Fn:Join [ ' ', [!Ref S3BucketName] ]
Key: Fn::Join [ ' ', [!Ref S3KeyName] ]
and
VersioningConfiguration:
Status: Suspended
Both of these are objects, not 'String (or simple type) properties'. The error is saying that the whole Parameters object must have only simple values.
Incidentally, TemplateURL needs to go outside the Parameters object.

AWS Cloudformation nested stack parameter type for parameter name does not exist

I'm trying to deploy a parent and nested stacks to AWS with cloudformation. The parent stack looks like this
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VPC:
Description: Choose which VPC the Lambda-functions should be deployed to
Type: AWS::EC2::VPC::Id
Default: vpc-sdjkfnsdjklfn
Subnets:
Description: Choose which subnets Lambda-functions should be deployed to
Type: CommaDelimitedList
Default: "subnet-sdoifno, subnet-sdofjnsdo"
SecurityGroup:
Description: Select the Security Group to use for the Lambda-functions
Type: AWS::EC2::SecurityGroup::Id
Default: sg-sdklfnsdkl
Role:
Description: Role for Lambda functions
Type: String
Default: arn:aws:iam::dlfksd:role/ssdfnsdo
Resources:
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: "my-api"
Description: "SPP Lambda API"
Stack1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: 'https://s3.amazonaws.com/bucket/template1.yml'
Parameters:
VPC: !Ref VPC
Subnets: !Join
- ','
- !Ref Subnets
SecurityGroup: !Ref SecurityGroup
Role: !Ref Role
RestApi: !Ref RestApi
ApiResourceParent: !GetAtt "RestApi.RootResourceId"
The child stack looks like this
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VPC:
Type: AWS::EC2::VPC::Id
Subnets:
Type: CommaDelimitedList
SecurityGroup:
Type: AWS::EC2::SecurityGroup::Id
Role:
Type: String
RestApi:
Type: AWS::ApiGateway::RestApi
ApiResourceParent:
Type: AWS::ApiGateway::Resource
Resources:
Fucntion:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: bucket
S3Key: node_lambdas.zip
Handler: Function.handler
Role: !Ref Role
Runtime: nodejs6.10
Timeout: 300
VpcConfig:
SecurityGroupIds:
- !Ref SecurityGroup
SubnetIds: !Ref Subnets
#Policies: AWSLambdaDynamoDBExecutionRole
Permission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt "Function.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/*/*"
Resource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestApi
ParentId: !Ref ApiResourceParent
PathPart: addadjustments
When I run aws cloudformation deploy --template-file parent-stack.yml --stack-name spp-lambda --region us-east-1 --capabilities CAPABILITY_IAM I get the following error
Embedded stack
arn:aws:cloudformation:us-east-1:771653148224:stack/spp-lambda-Stack1-97M9BLBUM3A5/4a454a50-c274-11e8-b49c-500c28903236
was not successfully created: Parameter validation failed: parameter
type AWS::ApiGateway::RestApi for parameter name RestApi does not
exist, parameter type AWS::ApiGateway::Resource for parameter name
ApiResourceParent does not exist
It doesn't complain about the parameters that are explicitly defined in the parent template. I want the parameters it is complaining about to be created and passed dynamically as I won't know the values before hand. What am I doing wrong?
Although some of the AWS resource type are supported as a cloudformation parameter type, it doesn't mean all resource type are supported.
You are trying to reference API gateway value as an AWS-specific parameter type, but it is not supported: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html#aws-specific-parameter-types
I believe using String as the type is sufficient.

Configuration of environment variables for different AWS Lambda aliases in CloudFormation template

I create CloudFormation template for my AWS Lambda function and I need to specify different values of environment variables for different lambda aliases.
My template looks like:
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Description: Lambda function configuration
Resources:
EndpointLambda:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: "endpoint-lambda"
Handler: "com.test.aws.RequestHandler::handleRequest"
Runtime: java8
Code:
S3Bucket: "lambda-functions"
S3Key: "test-endpoint-lambda-0.0.1.jar"
Description: Test Lambda function
MemorySize: 256
Timeout: 60
Environment:
Variables:
ES_HOST: test-es-host-url
ES_ON: true
ES_PORT: 443
ES_PROTOCOL: https
REDIS_URL: test-redis-host-url
QaLambdaAlias:
Type: "AWS::Lambda::Alias"
Properties:
FunctionName: !Ref EndpointLambda
FunctionVersion: 1
Name: "QA"
Description: "QA alias"
ProdLambdaAlias:
Type: "AWS::Lambda::Alias"
Properties:
FunctionName: !Ref EndpointLambda
FunctionVersion: 1
Name: "Prod"
Description: "Production alias"
As you see, I have two aliases - QA and Prod and bunch of environment variables. I specified variables with common values in lambda function declaration. But I need to declare for QA alias env. variable's values related to QA, and for Prod alias - values for Prod environment. Any ideas how can I do that?
You can use CloudFormation Parameters to do this. As a quick example:
Parameters:
LambdaRuntime:
Type: String
Default: 'java8'
Description: What Lambda runtime do we use?
Resources:
QaLambdaAlias:
Type: "AWS::Lambda::Alias"
Properties:
FunctionName:
Ref: EndpointLambda
FunctionVersion: 1
Name: "QA"
Description: "QA alias"
Runtime:
Ref: LambdaRuntime
Then, if you want to use a different parameter, when you deploy via CLI, you can override with parameter-overrides like this:
aws cloudformation deploy --stack-name MyStack --template-file \
CloudFormation/MyStack.yaml --capabilities CAPABILITY_IAM \
--parameter-overrides LambdaRuntime=nodejs8.10