Reference multiple Parameter Cloudformation AWS - aws-cloudformation

If I have some parameter like
Parameters:
Owner:
Description: Enter Team or Individual Name Responsible for the Stack.
Type: String
Default: Name
Project:
Description: Enter Project Name.
Type: String
Default: Whatever
is there a way to reference them both like:
Resources:
Resource:
Properties:
Name: !Ref Owner- !Sub ${Project}
merci A

You can do
Name: !Sub "${Owner}-${Project}"
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html#w2ab1c21c28c59b7

You can use:
Name: !Join [ '-', [!Ref Owner, !Ref Project] ]
Which will generate something like ownerX-projectY

Related

How to conditionally create an AWS::Events::Connection resource based on if a secret key is defined or not

I currently have this cloud formation template that is supposed to create an event bridge resource with all the necessary configurations, but I can't get it to create because I can't get cloud formation to verify if a key exists in the secrets manager or not.
to be more clear, I want my event-bridge.yml template resource to only be created if my key ${Stage}/${SubDomain}/django-events-api-key is already defined in the secrets manager and has a valid value(meaning it does not only have an empty string or a AWS::NoValue); this because I need to create the key after the stack is created and deployed, before the stack is not deployed, so I can't execute my command to generate the key
I have this:
event-bridge.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Event scheduling for sending the email digest"
Parameters:
SubDomain:
Description: The part of a website address before your DomainName - e.g. www or img
Type: String
DomainName:
Description: The part of a website address after your SubDomain - e.g. example.com
Type: String
Stage:
Description: Stage name (e.g. dev, test, prod)
Type: String
DjangoApiKey:
Description: Api key for events bridge communication
Type: String
Conditions:
DjangoApiKeyExists: !Or [ !Not [ !Equals [ !Ref DjangoApiKey, !Ref AWS::NoValue ] ], !Not [ !Equals [ !Ref DjangoApiKey, "" ] ] ]
Outputs:
DjangoEventsConnection:
Description: Connection to the Django backend for Event Bridge
Value: !Ref DjangoEventsConnection
Resources:
MessageDigestEventsRule:
Type: AWS::Events::Rule
Properties:
Name: !Sub "${SubDomain}-chat-digest"
Description: "Send out email digests for a chat"
ScheduleExpression: "rate(15 minutes)"
State: "ENABLED"
Targets:
- Arn: !GetAtt MessageDigestEventsApiDestination.Arn
HttpParameters:
HeaderParameters: { }
QueryStringParameters: { }
Id: !Sub "${SubDomain}-chat-digest-api-target"
RoleArn: !GetAtt MessageDigestEventsRole.Arn
EventBusName: "default"
DjangoEventsConnection:
Type: AWS::Events::Connection
Properties:
Name: !Sub "${SubDomain}-django"
AuthorizationType: "API_KEY"
AuthParameters:
ApiKeyAuthParameters:
ApiKeyName: "Authorization"
ApiKeyValue: !Ref DjangoApiKey
in a main.yml template I pass the key variable like this:
EventBridge:
DependsOn: [ VpcStack, DjangoEventBridgeApiKey ]
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./event-bridge.yaml
Parameters:
SubDomain: !Ref SubDomain
DomainName: !Ref DomainName
Stage: !Ref Stage
DjangoApiKey: !Sub '{{resolve:secretsmanager:arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${SubDomain}/django-events-api-key}}' <--
but that will always fail because the key is not defined, I would like to pass an empty string or something I can use as a conditional
I have also tried defining the secret, so it exists:
Resources:
DjangoEventBridgeApiKey:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub ${Stage}/${SubDomain}/django-events-api-key
Description: !Sub Credentials for the event bridge integration https://api.${SubDomain}.circular.co
Tags:
- Key: Name
Value: django-events-api-key
EventBridge:
DependsOn: [ VpcStack, DjangoEventBridgeApiKey ]
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./event-bridge.yaml
Parameters:
SubDomain: !Ref SubDomain
DomainName: !Ref DomainName
Stage: !Ref Stage
DjangoApiKey: !Sub '{{resolve:secretsmanager:${DjangoEventBridgeApiKey}}}'
But that for some reason, is still making my condition above fail, making the stack attempt to execute, I still cant figure out why is my condition not working
Any ideas on how to make this better? any help provided will be super useful to me
Okay found out the biggest problem with my implementation, on event-bridge.yml:
AWSTemplateFormatVersion: "2010-09-09"
Description: "Event scheduling for sending the email digest of chat messages"
Parameters:
SubDomain:
Description: The part of a website address before your DomainName - e.g. www or img
Type: String
DomainName:
Description: The part of a website address after your SubDomain - e.g. example.com
Type: String
Stage:
Description: Stage name (e.g. dev, test, prod)
Type: String
DjangoApiKey:
Description: Api key for events bridge communication
Type: String
Conditions:
DjangoApiKeyExists: !Not [ !Equals [ !Ref DjangoApiKey, "" ] ] # <-- this works
Outputs:
DjangoEventsConnection:
Condition: DjangoApiKeyExists
Description: Connection to the django backend for Event Bridge
Value: !Ref DjangoEventsConnection
Resources:
DjangoEventsConnection:
Type: AWS::Events::Connection
Condition: DjangoApiKeyExists
Properties:
Name: !Sub "${SubDomain}-django"
AuthorizationType: "API_KEY"
AuthParameters:
ApiKeyAuthParameters:
ApiKeyName: "Authorization"
ApiKeyValue: !Ref DjangoApiKey
# This does not update when we change the secret - so we need to force an update - need a more permanent solution
# ApiKeyValue: pop
MessageDigestEventsApiDestination:
Type: AWS::Events::ApiDestination
Condition: DjangoApiKeyExists
DependsOn: DjangoEventsConnection
on main.yml
...
DjangoEventBridgeApiKey:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub ${Stage}/${SubDomain}/django-events-api-key # <- this was missing ${Stage}
SecretString: " "
Tags:
- Key: Name
Value: django-events-api-key
EventBridge:
DependsOn: DjangoEventBridgeApiKey
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./event-bridge.yaml
Parameters:
SubDomain: !Ref SubDomain
DomainName: !Ref DomainName
Stage: !Ref Stage
DjangoApiKey: !Sub '{{resolve:secretsmanager:arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Stage}/${SubDomain}/django-events-api-key}}'
Tags:
- Key: Stage
Value: !Ref Stage
- Key: SubDomain
Value: !Ref SubDomain
- Key: SecretKeyName
Value: !Ref DjangoEventBridgeApiKey

While deploying stack encountered ' Unsupported ActionTypeId' error

When I create cloudformation stack for codepipeline, it fails and the error message is "Encountered unsupported property ActionTypeId".
Template is:
AWSTemplateFormatVersion: '2010-09-09'
Description: Model and provision AWS CodePipeline and AWS CodeBuild
Parameters:
CodePipelineSourceBucketName:
Type: String
Description: Bucket to store source code
Default: covid19-codepipeline-source
CodePipelineSourceObjectKey:
Type: String
Description: Object key of zip file uploaded to source bucket
Default: source.zip
CodePipelineArtifactStoreBucketName:
Type: String
Description: Bucket to store artifacts created by codepipeline
Default: covid19-codepipeline-artifacts
CloudTrailLogsBucketName:
Type: String
Description: Bucket to store cloudtrail logs
Default: covid19-cloudtrail-logs
Resources:
# CodePipeline
DeployPipelineForGlueWorkflow:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Sub DeployPipelineForGlueWorkflow-${AWS::StackName}
RoleArn: !GetAtt CodePipelineRole.Arn
ArtifactStore:
Type: S3
Location: !Ref CodePipelineArtifactStoreBucket
Stages:
-
Name: Source
Actions:
-
Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Version: "1"
Provider: S3
OutputArtifacts:
- Name: SourceOutput
Configuration:
S3Bucket: !Ref CodePipelineSourceBucket
S3ObjectKey: !Ref CodePipelineSourceObjectKey
PollForSourceChanges: false
RunOrder: 1
-
I checked the indentation as well but still facing same issue.

Is it possible to reuse pre-built Text in CloudFormation?

I have a few parameters passed to one of my CloudFormation conf file like this (YAML):
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation Template for creating pipeline workflow.
Parameters:
Opt1:
Description: my opt1
Type: String
Default: opt1_default
Opt2:
Description: my opt2
Type: String
Default: opt2_default
Opt3:
Description: my opt3
Type: String
Default: opt3_default
...
In many other parts of my conf I keep on use:
...
Name: !Sub '${Opt1}-${Opt2}-${Opt3}'
...
Name: !Sub '${Opt1}-${Opt2}-${Opt3}'
...
Name: !Sub '${Opt1}-${Opt2}-${Opt3}'
...
Is it possible to create some reference like:
SomeRef: !Sub '${Opt1}-${Opt2}-${Opt3}'
in a way that I can do:
...
Name: !Ref SomeRef
...
Name: !Ref SomeRef
...
Name: !Ref SomeRef
...
?
Nested template with no resources and single output can do it:
NameCreator.yaml
---
AWSTemplateFormatVersion: 2010-09-09
Description: 'Empty nested template'
Parameters:
Opt1:
Type: String
Opt2:
Type: String
Conditions:
Never: !Equals [ a, b ]
Resources:
NullResource:
Type: Custom::Null
Condition: Never
Outputs:
Name:
Value: !Sub '${Opt1}-${Opt2}'
And then in main template call it:
NameCreator:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
Opt1: !Ref Opt1
Opt2: !Ref Opt2
TemplateURL: https://mybucket.s3.amazonaws.com/NameCreator.yaml
and use it:
Name: !GetAtt 'NameCreator.Outputs.Name'

SAM API Gateway with Cloudformation WAFRegional

To secure our API, I'm trying to deploy a WAFRegional with a RateBasedRule. The API Gateway is located in a SAM template wherein I have also a nested stack for the child template holding the WAFRegional configurations. The child template for the WAFRegional configuration is provided below. What happens during the ExecuteChangeSet phase is the following:
CamerasIpSet is created
CamerasRateRule is created
WAFCamerasWebACL CREATE_FAILED: The referenced item does not exist. (Service: AWSWAFRegional; Status Code: 400; Error Code: WAFNonexistentItemException
I found the following post from about 2 months ago where someone has the same issue when using Serverless: https://forum.serverless.com/t/dependon-api-gateway-deployment/7792
What am I missing out on here?
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template for WAF Configuration'
Parameters:
CamerasApi:
Description: "Arn of the Cameras Api"
Type: String
Default: cameras-api-dev
StageName:
Description: "Stage name of the Cameras Api"
Type: String
Default: v
Blocking:
Description: "Number of calls per 5 minutes for WAF IP blocking."
Type: Number
Default: 2000
EnvironmentType:
Type: String
Default: "dev"
Description: "Type of environment: dev, staging or prod."
Resources:
WAFCamerasWebACL:
Type: AWS::WAFRegional::WebACL
DependsOn: CamerasRateRule
Properties:
DefaultAction:
Type: ALLOW
MetricName: !Join ['', ['IPBlockingMetric', !Ref EnvironmentType]]
Name: !Join ['', ['IPBlockingACL', !Ref EnvironmentType]]
Rules:
-
Action:
Type: "BLOCK"
Priority: 1
RuleId: !Ref CamerasRateRule
CamerasRateRule:
Type: AWS::WAFRegional::RateBasedRule
Properties:
MetricName: UnallowedAccessCount
Name: FiveMinuteRule
RateKey: IP
RateLimit: !Ref Blocking
MatchPredicates:
-
DataId: !Ref CamerasIpSet
Negated: false
Type: "IPMatch"
CamerasIpSet:
Type: AWS::WAFRegional::IPSet
Properties:
Name: !Join ['-', ['IpBlacklist', !Ref EnvironmentType]]
MyWebACLAssociation:
Type: AWS::WAFRegional::WebACLAssociation
Properties:
ResourceArn: !Sub arn:aws:apigateway:${AWS::Region}::/restapis/${CamerasApi}/stages/${StageName}
WebACLId: !Ref WAFCamerasWebACL
Outputs:
WebACL:
Description: Name of the web ACL
Value: !Ref WAFCamerasWebACL
I finally resolved the issue with the help of the AWS customer service. This is a limitation they have with CloudFormation when dealing with AWS::WAFRegional::RateBasedRule.
Despite the fact that CloudFormation supports creating WAF regional rate-based rules, the association of them with a Web ACL is not currently supported. If you observe link [1] below, you will realize that:
"To add the rate-based rules created through CloudFormation to a web ACL, use the AWS WAF console, API, or command line interface (CLI)."
[1] AWS::WAFRegional::RateBasedRule:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafregional-ratebasedrule.html
I used the Cloudformation template to generate the WebACL, the RateBasedRule, and the association of the WebACL with my APIGW. Using CodeBuild in our CI/CD pipeline, I'm now adding the RateBasedRule to the WebACL by using the CLI command aws waf-regional update-web-acl.
I ran in the same issue and I solve the problem with WAFv2
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template for WAF Configuration'
Parameters:
CamerasApi:
Description: "Arn of the Cameras Api"
Type: String
Default: YOUR-API-ID
StageName:
Description: "Stage name of the Cameras Api"
Type: String
Default: YOUR-Stage
Blocking:
Description: "Number of calls per 5 minutes for WAF IP blocking."
Type: Number
Default: 2000
EnvironmentType:
Type: String
Default: Prod
Description: "Type of environment: dev, staging or prod."
Resources:
WAFCamerasWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: ExampleWebACL
Description: This is an example WebACL
Scope: REGIONAL
DefaultAction:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: ExampleWebACLMetric
Rules:
- Name: RulesTest
Priority: 0
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: test
Statement:
RateBasedStatement:
Limit: 100
AggregateKeyType: IP
MyWebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Sub arn:aws:apigateway:${AWS::Region}::/restapis/${CamerasApi}/stages/${StageName}
WebACLArn: !GetAtt WAFCamerasWebACL.Arn
Outputs:
WebACL:
Description: Name of the web ACL
Value: !Ref WAFCamerasWebACL
Assuming a AWS::WAFRegional::WebACL and AWS::WAFRegional::RateBasedRule are defined in a Cloudformation stack, they can be attached using the following bash script:
CHANGE_TOKEN=$(aws waf-regional get-change-token --output text)
WEBACL_ID=$(aws waf-regional list-web-acls --query WebACLs[0].WebACLId --output text)
RULE_ID=$(aws waf-regional list-rate-based-rules --query Rules[0].RuleId --output text)
aws waf-regional update-web-acl --web-acl-id $WEBACL_ID --change-token $CHANGE_TOKEN \
--updates Action="INSERT",ActivatedRule='{Priority=1,RuleId="'$RULE_ID'",Action={Type="BLOCK"},Type="RATE_BASED"}'
However unfortunately this leads to issues when deleting the Cloudformation stack
The following resource(s) failed to delete: [RateBasedRuleName].
Any ideas how to enable the stack to remove the rule when issueing aws cloudformation delete-stack?
Resources:
BlueWafAlbAssociation:
Type: "AWS::WAFv2::WebACLAssociation"
Properties:
WebACLArn: arn:aws:wafv2:us-east-1:1234567890:regional/webacl/name-of-webacl/id-of-webacl
ResourceArn: arn:aws:elasticloadbalancing:us-east-1:1234567890:loadbalancer/app/load-balancer-name/xxxxxxxxxxx

Nested Fn::ImportValue in Fn::Sub not working for SAM template

Description:
I am trying to define Serverless API resource. But having trouble in defining location of swagger specification file using function ImportValue.
Steps to reproduce the issue:
I am not able to define AWS::Serverless::Api resource having nested function ImportValue in Location. I have tried following three ways, none of them work.
Note: Stack parameters are defined properly and export value from other stack exists. Not showing them here for brevity reason.
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::ImportValue:
!Sub "${EnvironmentName}-dist-bucket-${AWS::Region}"
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
!ImportValue 'dev-dist-bucket-us-east-1'
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::ImportValue: 'dev-dist-bucket-us-east-1'
Cloudformation shows following error.
FAILED - The value of parameter Location under transform Include must
resolve to a string, number, boolean or a list of any of these.
However, if I do not use ImportValue it works with a nested Fn::Sub
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::Sub: dist-bucket-${EnvironmentName}-${AWS::Region}
Is it because of Fn::Transform or AWS::Include?