Json format error in cloud formation template - amazon-web-services

I'm getting the error below from my cloud formation template. It happens when using json and pure yaml.
error
Resource handler returned message: "Invalid request provided: JSON not well-formed. at Line: 13, Column: 10 (Service: Ssm, Status Code: 400,
template with json
AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS CloudFormation Template for Response Plans"
Parameters:
Environment:
Type: String
Domain:
Type: String
Team:
Type: String
NotificationARN:
Type: AWS::SSM::Parameter::Value<String>
Default: /sandbox06/Topics/PolicyData/arn
Resources:
UpdateAliasResponsePlan:
Type: AWS::SSMIncidents::ResponsePlan
Properties:
Actions:
- SsmAutomation:
RoleArn: !Ref Role
DocumentName: UpdateAliasDocument
# ActionType: UpdateAlias
DisplayName: "UpdateLambdaAlias"
# Engagements:
# Engagements
IncidentTemplate:
Impact: 3
NotificationTargets:
- SnsTopicArn:
Ref: NotificationARN
Summary: "String"
Title: "String"
Name: "UpdateLambdaAlias"
Tags:
- Key: "Team"
Value: !Ref Team
- Key: "Domain"
Value: !Ref Domain
- Key: "Environment"
Value: !Ref Environment
UpdateAliasDocument:
Type: AWS::SSM::Document
Properties:
Content: |
{
"schemaVersion": "2.2",
"parameters": {
"Environment": { "type": "string"},
"Domain": { "type": "string"},
"Team": { "type": "string"},
"NotificationARN": { "type": "string", "default": "/sandbox06/Topics/PolicyData/arn"}
},
"mainSteps": [
{ "action": "aws:runShellScript",
"name": "runCommands",
"inputs": {
"runCommand": ["aws lambda update-functionconfiguration --function-name $FunctionArn --version $FunctionVersion"]
}
]
}
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: UpdateAliasPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- lambda:UpdateFunctionConfiguration
Resource:
- !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Environment}-*
template with yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS CloudFormation Template for Response Plans"
Parameters:
Environment:
Type: String
Domain:
Type: String
Team:
Type: String
NotificationARN:
Type: AWS::SSM::Parameter::Value<String>
Default: /sandbox06/Topics/PolicyData/arn
Resources:
UpdateAliasResponsePlan:
Type: AWS::SSMIncidents::ResponsePlan
Properties:
Actions:
- SsmAutomation:
RoleArn: !Ref Role
DocumentName: UpdateAliasDocument
# ActionType: UpdateAlias
DisplayName: "UpdateLambdaAlias"
# Engagements:
# Engagements
IncidentTemplate:
Impact: 3
NotificationTargets:
- SnsTopicArn:
Ref: NotificationARN
Summary: "String"
Title: "String"
Name: "UpdateLambdaAlias"
Tags:
- Key: "Team"
Value: !Ref Team
- Key: "Domain"
Value: !Ref Domain
- Key: "Environment"
Value: !Ref Environment
UpdateAliasDocument:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: "2.2"
parameters:
- name: FunctionVersion
type: "String"
defaultValue: "1"
- name: FunctionArn
type: "String"
mainSteps:
- action: aws:runShellScript
name: "runCommand"
inputs:
runCommand: "aws lambda update-function-configuration --function-name $FunctionArn --version $FunctionVersion"
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: UpdateAliasPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- lambda:UpdateFunctionConfiguration
Resource:
- !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Environment}-*
Another YAML Version
AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS CloudFormation Template for Response Plans"
Parameters:
Environment:
Type: String
Domain:
Type: String
Team:
Type: String
NotificationARN:
Type: AWS::SSM::Parameter::Value<String>
Default: /sandbox06/Topics/PolicyData/arn
Resources:
UpdateAliasResponsePlan:
Type: AWS::SSMIncidents::ResponsePlan
Properties:
Actions:
- SsmAutomation:
RoleArn: !Ref Role
DocumentName: UpdateAliasDocument
# ActionType: UpdateAlias
DisplayName: "UpdateLambdaAlias"
# Engagements:
# Engagements
IncidentTemplate:
Impact: 3
NotificationTargets:
- SnsTopicArn:
Ref: NotificationARN
Summary: "String"
Title: "String"
Name: "UpdateLambdaAlias"
Tags:
- Key: "Team"
Value: !Ref Team
- Key: "Domain"
Value: !Ref Domain
- Key: "Environment"
Value: !Ref Environment
UpdateAliasDocument:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: "2.2"
parameters:
- name: FunctionVersion
type: "String"
defaultValue: "1"
- name: FunctionName
type: "String"
mainSteps:
- name: UpdateLambdaAlias
action: aws:executeAWSApi
inputs:
Service: "lambda"
Api: UpdateFunctionConfiguration
FunctionName: $FunctionName
FunctionVersion: $FunctionVersion
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: UpdateAliasPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- lambda:UpdateFunctionConfiguration
Resource:
- !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Environment}-*

You're getting the error when it tries to resolve the SSM parameters. It is a 400 error, so it may be that you don't have permission to retrieve the parameter from SSM. In this case it is looking for /sandbox06/Topics/PolicyData/arn so verify that the account you are using to create the stack has permission to retrieve that parameter. This article shows the permissions needed.
If so, also verify that the value of that parameter in SSM would result in a valid template if you pasted it into your template. Verify that the SSM parameter is of type String, as AWS::SSM::Parameter::Value<String> is
A Systems Manager parameter whose value is a string. This corresponds
to the String parameter type in Parameter Store.
That link also mentions the following and gives an alternative if you are want to fetch a secure string:
AWS CloudFormation does not support defining template parameters as
SecureString Systems Manager parameter types.
Also, it may be that you need to format the default to not start with a slash. This page shows an example that does not start with a slash, or for hierarchical parameters that do begin with a slash, it may need to be in single quotes (Example 2 shows it that way)

The problem was with the way I was defining the parameters. I needed to remove the name key.
replace
UpdateAliasDocument:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: "2.2"
parameters:
- name: FunctionVersion
type: "String"
defaultValue: "1"
- name: FunctionName
type: "String"
mainSteps:
- name: UpdateLambdaAlias
action: aws:executeAWSApi
inputs:
Service: "lambda"
Api: UpdateFunctionConfiguration
FunctionName: $FunctionName
FunctionVersion: $FunctionVersion
with
UpdateAliasDocument:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: "2.2"
parameters:
FunctionVersion
type: "String"
defaultValue: "1"
FunctionName
type: "String"
mainSteps:
- name: UpdateLambdaAlias
action: aws:executeAWSApi
inputs:
Service: "lambda"
Api: UpdateFunctionConfiguration
FunctionName: $FunctionName
FunctionVersion: $FunctionVersion

Related

AWS::ApiGatewayV2::Api - Simple WebSocket configuration throwing INVALID_API_KEY (forbidden)

I did not set any authorization for the Websocket and it throws INVALID_API_KEY.
Here's SAM template:
##############################################################
# API GATEWAY: BrokerAuthenticateSocketApi
##############################################################
BrokerAuthenticateSocketApi:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: !Sub "${AWS::StackName}-BrokerAuthenticateSocketApi"
ProtocolType: WEBSOCKET
RouteSelectionExpression: "$request.body.action"
Tags:
'Joba:Product': !Ref Product
'Joba:Environment': !Ref Environment
ApiStage: # Why would we need this: https://medium.com/#TomKeeber/aws-api-gateways-c048cec63046
Type: AWS::ApiGatewayV2::Stage
Properties:
StageName: !Ref ApiStageName
AutoDeploy: true
ApiId: !Ref BrokerAuthenticateSocketApi
AccessLogSettings:
DestinationArn: !GetAtt ApiGatewayAccessLogGroup.Arn
Format: '{"requestTime":"$context.requestTime","requestId":"$context.requestId","routeKey":"$context.routeKey","status":$context.status,"responseLatency":$context.responseLatency,"integrationRequestId":"$context.integration.requestId","functionResponseStatus":"$context.integration.status","integrationLatency":"$context.integration.latency","integrationServiceStatus":"$context.integration.integrationStatus","ip":"$context.identity.sourceIp","userAgent":"$context.identity.userAgent","principalId":"$context.authorizer.principalId","validationErrorString":"$context.error.validationErrorString","integrationErrorMessage":"$context.integrationErrorMessage","errorMessage":"$context.error.message","errorResponseType":"$context.error.responseType"}'
Tags:
'Joba:Product': !Ref Product
'Joba:Environment': !Ref Environment
ApiAuthenticateRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref BrokerAuthenticateSocketApi
RouteKey: authenticate
AuthorizationType: NONE # TODO: change this for Auth0
OperationName: AuthenticateRoute
Target: !Join
- /
- - integrations
- !Ref ApiAuthenticateRouteIntegration
ApiAuthenticateRouteIntegration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref BrokerAuthenticateSocketApi
IntegrationType: AWS
IntegrationMethod: POST
IntegrationUri: !Sub "arn:aws:apigateway:${AWS::Region}:states:action/StartExecution"
CredentialsArn: !Sub "${ApiIntegrationStateMachineExecutionRole.Arn}"
TemplateSelectionExpression: \$default
RequestTemplates: # see: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-mapping-template-reference.html
"$default" :
Fn::Sub: >
#set($statesInput='{"data": ' + $input.body + ',"webSocket": {"connectionId": "' + $context.connectionId + '", "domainName": "' + $context.domainName + '"}' + '}')
#set($statesInput=$util.escapeJavaScript($statesInput).replaceAll("\\'","'"))
{
"input": "$statesInput",
"stateMachineArn": "${DownloadBrokerageNotesStateMachine}"
}
ApiAuthenticateRouteResponse: # https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-route-response.html
Type: AWS::ApiGatewayV2::RouteResponse
Properties:
RouteId: !Ref ApiAuthenticateRoute
ApiId: !Ref BrokerAuthenticateSocketApi
RouteResponseKey: $default
ApiAuthenticateRouteIntegrationResponse:
Type: AWS::ApiGatewayV2::IntegrationResponse
Properties:
ApiId: !Ref BrokerAuthenticateSocketApi
IntegrationId: !Ref ApiAuthenticateRouteIntegration
IntegrationResponseKey: $default
ApiIntegrationStateMachineExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "sts:AssumeRole"
Effect: Allow
Principal:
Service:
- !Sub apigateway.${AWS::Region}.amazonaws.com
Path: "/"
Policies:
- PolicyName: StateMachineExecutionAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "states:StartExecution"
Resource: !Ref DownloadBrokerageNotesStateMachine
Tags:
- Key: 'Joba:Product'
Value: !Ref Product
- Key: 'Joba:Environment'
Value: !Ref Environment
ApiGatewayAccessLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Join [ "/", [ "joba", "apigateway", !Ref BrokerAuthenticateSocketApi, "access-logs"]]
Using Postman to test, it connects successfully to the websocket:
When I try to send a message (with action=authenticate as configured in the SAM template), it returns Forbidden
The apigatway log shows INVALID_API_KEY.
{
"requestTime":"28/Jan/2023:22:32:34 +0000",
"requestId":"feZUdEH2oAMFe9A=",
"routeKey":"-",
"status":403,
"responseLatency":-,
"integrationRequestId":"-",
"functionResponseStatus":"-",
"integrationLatency":"-",
"integrationServiceStatus":"-",
"userAgent":"-","principalId":"-",
"validationErrorString":"-",
"integrationErrorMessage":"-",
"errorMessage":"Forbidden",
"errorResponseType":"INVALID_API_KEY"
}
In no section of the SAM template, I specified Authorization. In fact, I specified AuthorizationType: NONE in the AWS::ApiGatewayV2::Route.
What's wrong with my configuration?
It was really hard to find the error, but I did. A rather silly mistake, but not fully understood why it has to be like this.

AWS CloudFormation: How to refer a role defined in another stack inside AWS::IAM::Policy

Cloudformation Stack 1:
AWSTemplateFormatVersion: 2010-09-09
Metadata:
'AWS::CloudFormation::Designer':
c311c237-d7a4-4fac-a838-8a5a37a4b083:
size:
width: 60
height: 60
position:
x: 127
'y': 160
z: 0
Resources:
ECSRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'ec2:AttachNetworkInterface'
- 'ec2:CreateNetworkInterface'
- 'ec2:CreateNetworkInterfacePermission'
- 'ec2:DeleteNetworkInterface'
- 'ec2:DeleteNetworkInterfacePermission'
- 'ec2:Describe*'
- 'ec2:DetachNetworkInterface'
- 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
- 'elasticloadbalancing:DeregisterTargets'
- 'elasticloadbalancing:Describe*'
- 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
- 'elasticloadbalancing:RegisterTargets'
Resource: '*'
Outputs:
ECSTaskRoleId:
Description: ECSRoleId
Value: !GetAtt
- ECSRole
- RoleId
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', ECSTaskRoleId ] ]
ECSTaskRoleIdECSRole:
Description: The ARN of the ECS role
Value: !GetAtt 'ECSRole.Arn'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ]
**
Stack 2:**
Resources:
SNSRWPolicy:
Type: 'AWS::IAM::Policy'
Properties:
Role :
- Fn::ImportValue: 'testk2:ECSTaskRoleId'
PolicyName: test-snspolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'sns:Publish'
- 'kms:Decrypt'
- 'kms:GenerateDataKey'
Metadata:
'AWS::CloudFormation::Designer':
id: c5c7c890-30c7-470d-9233-57b8bd630856
I am getting below error
The role with name AROA3RRAFXNEDPVQKOLIW cannot be found. (Service: AmazonIdentityManagement; Status Code: 404; Error Code: NoSuchEntity; Request ID: d5ad937f-94c3-458e-a803-0c37258e05f1; Proxy: null)
How can I import IAM::Role to attach a policy in another stack?
Beginner in CloudFormation :(
The problem is that Type: 'AWS::IAM::Policy' property Roles expects a Role name and not role ID.
CloudFormation is quite sensitive to names vs ID. So always ensure that you mention correct property.
Outputs:
ECSTaskRole:
Description: The ECSRole name
Value: !Ref ECSRole
So while exporting it will export the name and importValue will take the name properly.
AWS::IAM::Policy Roles

ARN as a parameter in Cloud Formation Stack

I wanted to use the ARN as parameter input to cloudformation stack resources EventRuleRegion1 - Target as well as EventBridgeIAMrole , but it is not working. when i call with Ref function
Original ARN
arn:aws:events:ap-southeast-2:123456789123:event-bus/central-eventbus-sydney
When i give the arn directly in code its working fine.
Code
AWSTemplateFormatVersion: 2010-09-09
Parameters:
EventBridgeName:
Description: Enter the Event Bridge Name
Type: String
Default: ec2-lifecycle-events
EventBusName:
Description: Enter the Central Event Bus Name
Type: String
Default: central-eventbus-sydney
EventBusArn:
Description: Enter the ARN of Central Event Bus
Type: String
Default: arn:aws:events:ap-southeast-2:123456789123:event-bus/central-eventbus-sydney
Monitoringaccount:
Description: Enter the Monitoring AWS account number
Type: String
Default: 123456789123
Resources:
EventRuleRegion1:
Type: AWS::Events::Rule
Properties:
Description: Event rule to send events to monitoring account event bus
EventBusName: default
EventPattern:
source:
- aws.ec2
detail-type:
- "EC2 Instance State-change Notification"
detail:
state:
- "running"
- "stopped"
- "terminated"
Name: !Ref EventBridgeName
State: ENABLED
Targets:
- Arn: >-
- !Join [ "", [ !Sub "arn:aws:events:${AWS::Region}:123456789123:event-bus/",!Ref EventBusName ] ]
Id: !Ref EventBusName
RoleArn: !GetAtt
- EventBridgeIAMrole
- Arn
EventBridgeIAMrole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: !Sub events.amazonaws.com
Action: 'sts:AssumeRole'
Path: /
Policies:
- PolicyName: PutEventsDestinationBus
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'events:PutEvents'
Resource:
- >-
- !Join [ "", [ !Sub "arn:aws:events:${AWS::Region}:123456789123:event-bus/",!Ref EventBusName ] ]
Error
Parameter - !Join [ "", [ !Sub "arn:aws:events:${AWS::Region}:123456789123:event-bus/",!Ref EventBusName ] ] is not valid. Reason: Provided Arn is not in correct format. (Service: AmazonCloudWatchEvents; Status Code: 400; Error Code: ValidationException; Request ID: 0d52a1d6-095e-44f7-9455-b7481dc4fb8d; Proxy: null)
The use of >- will result in literal strings, not evaluation of your CFN functions (join, ref). It should be:
Targets:
- Arn: !Join [ "", [ !Sub "arn:aws:events:${AWS::Region}:123456789123:event-bus/",!Ref EventBusName ] ]

Pass lambda function name to uri in swagger file

I am creating an api gateway with cloudformation. Actually I am using a swagger.yaml which is uploaded in s3 as body. I want to keep the swagger.yaml parameterized, but I can't pass the arn of my lambda function to the file. I have tried some solutions but nothing seems to work for me. I hope anyone can help me here.
Api GW:
AWSTemplateFormatVersion: 2010-09-09
Description: API
Parameters:
application:
Type: String
Default: test
apiGatewayName:
Type: String
Default: hub
apiGatewayStageName:
Type: String
AllowedPattern: "[a-z0-9]+"
Default: dev
apiGatewayHTTPMethod:
Type: String
Default: GET
lambdaFunctionName:
Type: String
AllowedPattern: "[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+"
Default: crawler
############################ REST API ############################
Resources:
apiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
EndpointConfiguration:
Types:
- REGIONAL
BodyS3Location:
Bucket: !Sub ${application}-${apiGatewayStageName}-${AWS::AccountId}
Key: api_swagger.yml
Name: !Ref apiGatewayName
Tags:
-
Key: Project
Value: test
apiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref apiGateway
StageName: !Ref apiGatewayStageName
Tags:
-
Key: Project
Value: test
############################ usagePlan ############################
usagePlan:
Type: 'AWS::ApiGateway::UsagePlan'
DependsOn:
apiKey
Properties:
ApiStages:
- ApiId: !Ref apiGateway
Stage: !Ref apiGatewayStageName
Description: test usage plan
Quota:
Limit: 1000
Period: MONTH
Throttle:
BurstLimit: 200
RateLimit: 100
UsagePlanName: ${application}-usageplan
Tags:
-
Key: Project
Value: test
usagePlanKey:
Type: 'AWS::ApiGateway::UsagePlanKey'
DependsOn:
usagePlan
Properties:
KeyId: !Ref apiKey
KeyType: API_KEY
UsagePlanId: !Ref usagePlan
Tags:
-
Key: Project
Value: test
############################ apiKey ############################
apiKey:
Type: AWS::ApiGateway::ApiKey
DependsOn:
- apiGatewayDeployment
- apiGateway
Properties:
CustomerId: String
Description: ApiKey for ${application}-api
Enabled: True
Name: ${application}-apikey
StageKeys:
- RestApiId: !Ref apiGateway
StageName: !Ref apiGatewayStageName
Tags:
-
Key: Project
Value: test
############################ apiGatewayRootMethod ############################
lambdaRootMethodInvoke:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt lambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/POST/
Tags:
-
Key: Project
Value: test
############################ applicationRuleBufferZoneMethod ############################
lambdaBufferZoneInvoke:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt lambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/${apiGatewayHTTPMethod}/application/rule/bufferZoneList
Tags:
-
Key: Project
Value: test
############################ Lambda Functions ############################
lambdaFunction:
Type: AWS::Lambda::Function
DependsOn:
- apiGateway
Properties:
Layers:
- arn:aws:lambda:eu-central-1:770693421928:layer:Klayers-python38-boto3:108
Code:
S3Bucket: !Sub ${application}-${apiGatewayStageName}-${AWS::AccountId}
S3Key: crawler.zip
Description: DynamoDB Crawler
FunctionName: !Ref lambdaFunctionName
Handler: crawler.lambda_handler
MemorySize: 128
Role: !GetAtt lambdaIAMRole.Arn
Runtime: python3.8
Tags:
-
Key: Project
Value: test
############################ Lambda IAM Role ############################
lambdaIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Policies:
- PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- dynamodb:DeleteItem
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:Query
- dynamodb:Scan
- dynamodb:UpdateItem
Effect: Allow
Resource: "*"
PolicyName: dynamoDBAccess
- PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Effect: Allow
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*
PolicyName: cloudWatchLogs
Tags:
-
Key: Project
Value: test
lambdaLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${lambdaFunctionName}
RetentionInDays: 90
Tags:
-
Key: Project
Value: test
############################ Output ############################
Outputs:
apiGatewayInvokeURL:
Value: !Sub https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}
BucketUrl:
Value: !Sub s3://${application}-${apiGatewayStageName}-${AWS::AccountId}/api_swagger.yml
swagger.yaml
openapi: 3.0.1
info:
title: Label Hub
termsOfService: http://swagger.io/terms/
contact:
email: apiteam#swagger.io
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
externalDocs:
description: Find out more about Swagger
url: http://swagger.io
servers:
- url: https://example.labelhub.de/v2
security:
- api_key: []
paths:
/application/rule/bufferZoneList:
get:
tags:
- application
summary: Returns list of buffer zones per field object for drift management
description: Returns a map of status codes to quantities
operationId: getApplicationRuleDrift
parameters:
- name: pName
in: query
required: true
schema:
type: string
- name: cCode
in: query
required: true
schema:
type: string
- name: cType
in: query
required: true
schema:
type: string
- name: nType
in: query
schema:
type: string
- name: timing
in: query
schema:
type: string
- name: rate
in: query
schema:
type: string
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/bufferZoneList'
x-amazon-apigateway-integration:
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaFunction.Arn}/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
components:
schemas:
crop:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
cropTypeList:
type: array
items:
$ref: '#/components/schemas/crop'
bufferZone:
type: object
properties:
bufferZone:
type: integer
example: 5
unit:
type: string
example: m
areaType:
type: string
example: WATERBODY_VEGETATED
bufferZoneList:
type: array
items:
$ref: '#/components/schemas/bufferZone'
layout:
required:
- "name"
type: "object"
properties:
id:
type: "integer"
format: "int64"
name:
type: "string"
status:
type: "string"
description: "label layout status in the application"
enum:
- "available"
- "pending"
MODEL444ead:
type: "object"
properties:
file:
type: "string"
description: "file to upload"
format: "binary"
apiResponse:
type: "object"
properties:
code:
type: "integer"
format: "int32"
type:
type: "string"
message:
type: "string"
product:
type: "object"
properties:
id:
type: "integer"
format: "int64"
name:
type: "string"
MODEL6f7c6f:
type: "object"
additionalProperties:
type: "integer"
format: "int32"
securitySchemes:
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
Any solutions to pass the uri to my swagger file ?
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html
The documentation includes the follow note:
We don't currently support using shorthand notations for YAML snippets.
Instead of
uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:crawler/invocations"
use
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations
!Sub is shorthand notation so won't be supported
Edit:
Issue with swagger.yaml
x-amazon-apigateway-integration:
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaFunction.Arn}/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
The above is incorrect YAML due to wrong indentation of the Fn::Sub line. Change this to:
x-amazon-apigateway-integration:
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaFunction.Arn}/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
Issue with template.yaml
Resources:
apiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
EndpointConfiguration:
Types:
- REGIONAL
BodyS3Location:
Bucket: !Sub ${application}-${apiGatewayStageName}-${AWS::AccountId}
Key: api_swagger.yml
Name: !Ref apiGatewayName
Tags:
-
Key: Project
Value: test
should be
Resources:
apiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
EndpointConfiguration:
Types:
- REGIONAL
Body:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: !Sub "s3://{application}-${apiGatewayStageName}-${AWS::AccountId}/api_swagger.yml"
Name: !Ref apiGatewayName
Tags:
-
Key: Project
Value: test
As the very first link of my answer mentions, the include transform is required (and was the basis of my original answer!).
After fixing both these issues, I got a circular dependency issue. Since this is outside the scope of your original question and I did not want to spend time debugging more issues, I did not make any more changes, but here are some resources to help you with that:
https://aws.amazon.com/blogs/infrastructure-and-automation/handling-circular-dependency-errors-in-aws-cloudformation/
Work around circular dependency in AWS CloudFormation

Cloudformation Unable to Use Outputted Parameters with Nested Stacks

I'm trying my hand at Cloudformation nested stacks. The idea is that I create a VPC, S3 bucket, Codebuild project, and Codepipeline pipeline using Cloudformation.
My Problem: Cloudformation is saying that the following parameters (outputted by child stacks) require values:
Vpc
PrivateSubnet1
PrivateSubnet2
PrivateSubnet3
BucketName
These params should have values as the value exists when I look at a completed child stack in the console.
I'll just show the templates for the parent, s3, and codepipeline. With regards to these three templates the problem is that I am unable to use an output BucketName from S3Stack in my CodePipelineStack
My Code:
cfn-main.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: root template for codepipeline poc
Parameters:
BucketName:
Type: String
VpcName:
Description: name of the vpc
Type: String
Default: sandbox
DockerUsername:
Type: String
Description: username for hub.docker
Default: seanturner026
DockerPassword:
Type: String
Description: password for hub.docker
Default: /codebuild/docker/password
Environment:
Type: String
Description: environment
AllowedValues:
- dev
- prod
Default: dev
Vpc:
Type: AWS::EC2::VPC::Id
PrivateSubnet1:
Type: AWS::EC2::Subnet::Id
PrivateSubnet2:
Type: AWS::EC2::Subnet::Id
PrivateSubnet3:
Type: AWS::EC2::Subnet::Id
GithubRepository:
Type: String
Description: github repository
Default: aws-codepipeline-poc
GithubBranch:
Type: String
Description: github branch
Default: master
GithubOwner:
Type: String
Description: github owner
Default: SeanTurner026
GithubToken:
Type: String
Description: github token for codepipeline
NoEcho: true
Resources:
VpcStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
VpcName: !Ref VpcName
TemplateURL: resources/vpc.yaml
S3Stack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: resources/s3.yaml
CodeBuildStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
Environment: !Ref Environment
DockerUsername: !Ref DockerUsername
DockerPassword: !Ref DockerPassword
Vpc: !GetAtt VpcStack.Outputs.VpcId
PrivateSubnet1: !GetAtt VpcStack.Outputs.PrivateSubnetId1
PrivateSubnet2: !GetAtt VpcStack.Outputs.PrivateSubnetId2
PrivateSubnet3: !GetAtt VpcStack.Outputs.PrivateSubnetId3
TemplateURL: resources/codebuild.yaml
CodePipelineStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
Environment: !Ref Environment
GithubRepository: !Ref GithubRepository
GithubBranch: !Ref GithubBranch
GithubOwner: !Ref GithubOwner
GithubToken: !Ref GithubToken
S3: !GetAtt S3Stack.Outputs.BucketName
TemplateURL: resources/codepipeline.yaml
s3.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: s3 bucket for aws codepipeline poc
Resources:
S3:
Type: "AWS::S3::Bucket"
Properties:
BucketName: "aws-sean-codepipeline-poc"
Outputs:
BucketName:
Description: S3 bucket name
Value: !Ref S3
codepipeline.yaml -- Please see ArtifactStore. This is where cloudformation is seeing my parameter BucketName as value-less.
AWSTemplateFormatVersion: 2010-09-09
Description: codepipeline for aws codepipeline poc
Parameters:
BucketName:
Type: String
Environment:
Type: String
Description: environment
AllowedValues:
- dev
- prod
Default: dev
GithubRepository:
Type: String
Description: github repository
Default: aws-codepipeline-poc
GithubBranch:
Type: String
Description: github branch
Default: master
GithubOwner:
Type: String
Description: github owner
Default: SeanTurner026
GithubToken:
Type: String
Description: github token for codepipeline
NoEcho: true
Resources:
CodePipelineRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: !Join
- ""
- - !Ref AWS::StackName
- "-code-pipeline-role-"
- !Ref Environment
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
Effect: "Allow"
Principal:
Service: "codepipeline.amazonaws.com"
Action: "sts:AssumeRole"
CodePipelinePolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: !Join
- ""
- - !Ref AWS::StackName
- "-code-pipeline-policy-"
- !Ref Environment
PolicyDocument:
Version: "2012-10-17"
Statement:
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- s3:putObject
- s3:getObject
- codebuild:*
Resource:
- "*"
Roles:
- !Ref CodePipelineRole
Pipeline:
Type: "AWS::CodePipeline::Pipeline"
Properties:
Name: !Join
- ""
- - "code-pipeline-poc-"
- !Ref AWS::StackName
ArtifactStore:
Location: !Ref BucketName
Type: S3
RestartExecutionOnUpdate: true
RoleArn: !Join
- ""
- - "arn:aws:iam::"
- !Ref AWS::AccountId
- ":role/"
- !Ref CodePipelineRole
Stages:
- Name: checkout-source-code
Actions:
- Name: SourceAction
RunOrder: 1
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: 1
Configuration:
Owner: !Ref GithubOwner
Repo: !Ref GithubRepository
Branch: !Ref GithubBranch
PollForSourceChanges: true
OAuthToken: !Ref GithubToken
OutputArtifacts:
- Name: source-code
- Name: docker-build-push
Actions:
- Name: build-push-job
RunOrder: 1
InputArtifacts:
- Name: source-code
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref BuildPushJob
OutputArtifacts:
- Name: build-push-job
Sorry if this is too verbose. If missed above, the problem is that ArtifactStore in the codepipeline.yaml is seeing my parameter BucketName as value-less, despite the value being outputted by S3Stack.
You pass the parameter as S3 but the template is expecting it as BucketName.