How to resolve AWS REST API-method circular dependency in CloudFormation - aws-cloudformation

I'm creating an AWS API Gateway that exposes a GET method on its root.
My GW:
`
MyApiGateway:
Type: "AWS::Serverless::Api"
DependsOn: GetRequest
Properties:
Name: !Sub my-api-${EnvironmentName}
The DependsOn is according to the docs: "If you create an AWS::ApiGateway::RestApi resource and its methods (using AWS::ApiGateway::Method) in the same template as your deployment, the deployment must depend on the RestApi's methods"
My method:
GetRequest:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: AWS_IAM
HttpMethod: GET
RestApiId: !Sub my-api-${EnvironmentName}
ResourceId: !GetAtt MyApiGateway.RootResourceId
`
And it depends on the GW again according to the docs: "The ID of an API Gateway resource. For root resource methods, specify the RestApi root resource ID, such as { "Fn::GetAtt": ["MyRestApi", "RootResourceId"] }."
This CloudFormation template cannot be built due to the circular dependency.
How can I expose a GET method on the API GW's root path without causing this circular dependency?
I tried removing the DependsOn section, and got the error "No integration defined for method"

Related

IAM permission to retrieve LaunchTemplate's LatestVersionNumber attribute in AWS::AutoScaling::AutoScalingGroup

While developing a CloudFormation template, I am following the principle of least privilege. So I am providing CloudFormation a role to assume, and which has the minimal set of privileges.
The template contains an AWS::AutoScaling::AutoScalingGroup which is based on a AWS::EC2::LaunchTemplate:
ECSAutoScalingGroup:
DependsOn: ECSCluster
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier: !Ref Subnets
LaunchTemplate:
LaunchTemplateId: !Ref ECSLaunchTemplate
Version: !GetAtt ECSLaunchTemplate.LatestVersionNumber
MinSize: 1
MaxSize: 2
DesiredCapacity: 1
...
ECSLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Metadata:
AWS::CloudFormation::Init:
...
Properties:
LaunchTemplateName: test-template
LaunchTemplateData:
...
When I create a CloudFormation stack out of this template, I get the following error on the ECSAutoScalingGroup resource:
Failed to retrieve attribute [LatestVersionNumber] for resource
[ECSLaunchTemplate]: You are not authorized to perform this operation.
(Service: AmazonEC2; Status Code: 403; Error Code:
UnauthorizedOperation; Request ID:
e0f01fd0-ee2a-4260-94f4-3c65177d05ee; Proxy: null)
Which IAM policy should I add to the IAM Role which is assumed by CloudFormation? Clearly, if I give it AdministratorAccess, it succeeds. However, I would like to follow the principal of least privilege.
Any ideas?
Thanks.
Answering my own question here. One should add these 2 actions to their IAM Role policy:
ec2:DescribeLaunchTemplates
ec2:DescribeLaunchTemplateVersions

How to configure IAM authorizer for HTTP ApiGateway in AWS SAM?

We have a service build with AWS SAM. Now we want to add authentication to it. We have one HTTP ApiGateway and we want to add an IAM authenticator to it. Unfortunately, I can't find any example or documentation on how to do that? I've tried, following options:
exampleApi:
Type: AWS::Serverless::HttpApi
Properties:
CorsConfiguration: True
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location: 'openapi.yaml'
StageName: v2
Auth:
DefaultAuthorizer: AWS_IAM
and
exampleApi:
Type: AWS::Serverless::HttpApi
Properties:
CorsConfiguration: True
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location: 'openapi.yaml'
StageName: v2
fnExample:
Type: AWS::Serverless::Function
Properties:
Handler: index.example
Role: !GetAtt dataLambdaRole.Arn
Events:
getExample:
Type: HttpApi
Properties:
Path: /example
Method: get
ApiId: !Ref exampleApi
Auth:
Authorizer: AWS_IAM
unfortunately, both of them finish with error. Can I ask you to share an example or instruction on how to configure the IAM authorizer for HTTP ApiGateway in AWS SAM template.
I think I found it.
Unfortunately, it looks that currently (21 January 2021) it is impossible to confiure IAM security for HTTP API using SAM template. This is what I found in AWS documentation:
Mechanisms for controlling access
AWS::Serverless::HttpApi
AWS::Serverless::Api
Lambda authorizers
✓
✓
IAM permissions
✓
Amazon Cognito user pools
✓
✓
API keys
✓
Resource policies
✓
OAuth 2.0/JWT authorizers
✓
More details can be found here
There is some work on AWS side to fix that:
https://github.com/aws/serverless-application-model/pull/1876
https://github.com/aws/serverless-application-model/pull/1878

What is the format to specify an external EDGE Gateway ApiId in CloudFormation templates?

I'm trying to create or update a stack with the following CloudFormation Template:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ApiGatewayId:
Type: String
ApiLayerArn:
Type: String
JarLocation:
Type: String
Resources:
Function:
Type: 'AWS::Lambda::Function'
Properties:
Handler: net.bitsandpaper.api.kiosk.PlatformChecker
Runtime: java11
Code:
S3Bucket: bnp-build-artifacts
S3Key: !Ref JarLocation
Description: ''
MemorySize: 128
Timeout: 5
Role: arn:aws:iam::479832603967:role/bnp-api-lambda-execution-role
Layers:
- !Ref ApiLayerArn
ApiIntegration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ApiGatewayId
IntegrationType: AWS_PROXY
IntegrationUri: !Join
- ''
- - 'arn:'
- !Ref 'AWS::Partition'
- ':apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- !Ref Function
- /invocations
TimeoutInMillis: 6000
ApiRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /kiosk/platform-check'
Target: !Join
- /
- - integrations
- !Ref ApiIntegration
The parameters are correctly passed by an external file, they look good in the Web Console, notably parameter ApiGatewayId has value 8548rqrsm5. Yet during deployment I have a CREATE_FAILED for ApiIntegration, with the message:
Invalid API identifier specified 479832603967:8548rqrsm5 (Service:
AmazonApiGatewayV2; Status Code: 404; Error Code: NotFoundException;
Request ID: 84918a83-cf9d-48d2-acf7-18d9d2e4d330; Proxy: null)
The API is an EDGE Rest API, in the same region than the CloudFormation stack. The ID is retrieved by the CLI with aws apigateway get-rest-apis.
Am I missing something in the ApiId format? The litterature is very scarce when not referencing an API in the same stack...
AWS::ApiGatewayV2 is only for WEBSOCKTES and HTTP types. From docs:
The API protocol. Valid values are WEBSOCKET or HTTP.
But since you are writing about Edge-optimized (not supported by HTTP api) it seems to that you are using REST API, rather then HTTP API. So you should be using AWS::ApiGateway resources, not AWS::ApiGatewayV2.
It seem's like the AWS::ApiGatewayV2::Route is created before the AWS::ApiGatewayV2::Integration. So When it trying to refer ApiIntegration it is not yet created.
So you should try to use DependsOn attribute.
With the DependsOn attribute you can specify that the creation of a
specific resource follows another. When you add a DependsOn attribute
to a resource, that resource is created only after the creation of the
resource specified in the DependsOn attribute.
Try this below CloudFormation code:
ApiRoute:
Type: AWS::ApiGatewayV2::Route
DependsOn: ApiIntegration
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /kiosk/platform-check'
Target: !Join
- /
- - integrations
- !Ref ApiIntegration
I hope this will help you out to resolve your problem.
Link: DependsOn Attribute UserGuide

Cloudformation circular dependency - Route53 and Cloudfront

Trying to configure a Route53 and Cloudfront resource but they seem to have an implicit circular dependency on each other. Is there an elegant solution for it?
The snippet of my cloudformation template is below:
AppDnsRecord:
Type: "AWS::Route53::RecordSetGroup"
DependsOn: CloudFrontDistributionApp
Properties:
HostedZoneName: example.com.
RecordSets:
- Name: !Sub "app-${StackName}.example.com."
Type: CNAME
TTL: "60"
ResourceRecords:
- !GetAtt "CloudFrontDistributionApp.DomainName"
CloudFrontDistributionApp:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Aliases:
- !Sub "app-${StackName}.example.com"
# ...
The issue is that the CNAME record depends on the Cloudfront's domain name and has a dependsOn. However the Cloudfront's Aliases configuration requires the CNAME to exist.

API Gateway HTTP Proxy integration with serverless-offline (NOT Lambda Proxy)

I am trying to use serverless-offline to develop / simulate my API Gateway locally. My API gateway makes liberal use of the HTTP proxy integrations. The production Resource looks like this:
I have created a serverless-offline configuration based on a few documents and discussion which say that it is possible to define an HTTP Proxy integration using Cloud Formation configuration:
httpProxyWithApiGateway.md - Setting an HTTP Proxy on API Gateway by using Serverless framework.
Setting an HTTP Proxy on API Gateway (official Serverless docs: API Gateway)
I have adapted the above two configuration examples for my purposes, see below.
Have any tips, for what I might be doing wrong here?
plugins:
- serverless-offline
service: company-apig
provider:
name: aws
stage: dev
runtime: python2.7
resources:
Resources:
# Parent APIG RestApi
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: company-apig
Description: 'The main entry point of the APIG'
# Resource /endpoint
EndpointResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
PathPart: 'endpoint'
RestApiId:
Ref: ApiGatewayRestApi
# Resource /endpoint/{proxy+}
EndpointProxyPath:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Ref: EndpointResource
PathPart: '{proxy+}'
RestApiId:
Ref: ApiGatewayRestApi
# Method ANY /endpoint/{proxy+}
EndpointProxyAnyMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: ANY
Integration:
IntegrationHttpMethod: ANY
Type: HTTP_PROXY
Uri: http://endpoint.company.cool/{proxy}
PassthroughBehavior: WHEN_NO_MATCH
MethodResponses:
- StatusCode: 200
ResourceId:
Ref: EndpointProxyPath
RestApiId:
Ref: ApiGatewayRestApi
For the above configuration, I get this output. Apparently, the configuration registers no routes at all.
{
"statusCode":404,
"error":"Serverless-offline: route not found.",
"currentRoute":"get - /endpoint/ping",
"existingRoutes":[]
}
Related: I am also attempting to solve the same problem using aws-sam, at the following post - API Gateway HTTP Proxy integration with aws-sam (NOT Lambda Proxy)
By default serverless-offline doesn't parse your resources for endpoints, enable it via custom config.
custom:
serverless-offline:
resourceRoutes: true
Ends up serving:
Serverless: Routes defined in resources:
Serverless: ANY /endpoint/{proxy*} -> http://endpoint.company.cool/{proxy}
Serverless: Offline listening on http://localhost:3000
Documentation