How to configure IAM authorizer for HTTP ApiGateway in AWS SAM? - aws-api-gateway

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

Related

How to resolve AWS REST API-method circular dependency in 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"

Enabling CloudWatch logs for ApiGateway?

Im trying to use CloudFormation to configure CloudWatch logs for an ApiGateway. Please see the settings I need in the attached picture (I cant post images into this topic just yet as I'm a new user)
CloudWatch logs for Api
Here is what I have tried so far however CloudWatch logs aren't enabled. Can anyone help with this?
apiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: apiGatewayRootMethod
Properties:
Description: API Deployment
RestApiId: !Ref apiGatewayApi
StageName: MyApi
StageDescription:
MetricsEnabled: True
MethodSettings:
- ResourcePath: "/*"
HttpMethod: "*"
LoggingLevel: INFO
MetricsEnabled: True
The AWS documentation is pretty unclear. After some days of shotgun programming, I found this. Here is a Cloudformation with API Gateway v2 that worked for me:
MyLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/apigateway/nameOfLogGroupForCloudWatch
RetentionInDays: 7
MyStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
# Begin CloudWatch
AccessLogSettings:
DestinationArn: !GetAtt MyLogGroup.Arn # This points to the log group above
Format: '{ "requestId": "$context.requestId", "path": "$context.path", "routeKey": "$context.routeKey", "ip": "$context.identity.sourceIp", "requestTime": "$context.requestTime", "httpMethod": "$context.httpMethod","statusCode": $context.status }'

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 create role with policy attached with cloud formation template?

I have a lambda function that needs to talk to few aws services like (EC2, other lambda functions, api gateway, Elastic Search service). all of these services are inside a private subnet in an exsiting vpc. How do i add a policy/role via cloudformation template such that i give access my lambda function to communicate with these other services. also , do i need to define a security group. right now there is a default security group applied to all of resources which doesn't have any inbound/outbound rules.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
VPCId:
Type: AWS::EC2::VPC::Id
Resources:
# S3 Bucket
S3Bucket:
Type: AWS::S3::Bucket
# Functions
S3-Lambda-trigger:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: lambda.handler
Description: s3 object creation triggers lambda
Runtime: nodejs12.x
Events:
S3Bucket:
Type: S3
Properties:
Bucket: !Ref S3Bucket
Events: 's3:ObjectCreated:*'
# Permissions
Allow-lamda-invocation-s3:
Type: AWS::Lambda::Permission
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref S3-Lambda-trigger
Principal: s3.amazonaws.com
SourceArn: !GetAtt S3Bucket.Arn

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