Generate Resource Logical Id name using a parameter in Sam template - aws-lambda

I am using Sam template to deploy a lambda with a api gateway.
Trying to generate a custom resource Logical Id based on a Timestamp. for eg in example below: ApiDeployment$TIMESTAMP$: which is not working. Any ideas how I may achieve a dynamically configurable resource Logical Id name, using Sam template?
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Setup our API Gateway instances
Parameters:
StageName:
Type: String
Default: 'example_stage'
Description: 'The name of the stage to be created and managed within our API Gateway instance.'
Resources:
Api:
Type: AWS::ApiGateway::RestApi
Properties:
Name: ExampleApi
EndpointConfiguration:
Types:
- REGIONAL
# The body should contain the actual swagger
Body: $SWAGGER_DEFINITION$
# Timestamp is added so that each deployment is unique. Without a new timestamp, the deployment will not actually occur
ApiDeployment$TIMESTAMP$:
Type: AWS::ApiGateway::Deployment
DependsOn: [ Api ]
# we want to retain our deployment history
DeletionPolicy: Retain
Properties:
RestApiId:
Ref: Api
ApiStage:
Type: AWS::ApiGateway::Stage
DependsOn: [ApiDeployment$TIMESTAMP$]
Properties:
RestApiId:
Ref: Api
DeploymentId:
Ref: ApiDeployment$TIMESTAMP$
StageName: {Ref: StageName}
MethodSettings:
- ResourcePath: "/*"
HttpMethod: "*"
LoggingLevel: INFO
MetricsEnabled: true
DataTraceEnabled: true
Outputs:
Endpoint:
Description: Endpoint url
Value:
Fn::Sub: 'https://${Api}.execute-api.${AWS::Region}.amazonaws.com'

Related

why isn't api registered when component is created

I have created a backstage scaffolding template to create a Spring boot rest service deployed to AWS EKS. When a component is created from it in backstage the api is not registered in backstage: the component builds using github actions, is deployed to AWS EKS and is registered in backstage.
catalog-info.yaml includes
spec:
type: service
lifecycle: experimental
owner: "team-a"
system: experimental-portal
providesApis:
- stephendemo16
consumesApis:
- petstore
To experiment I added petstore under consumesApis and it is registered in backstage.
I have a backstage yaml file greeting-api.yaml defining my API
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: stephendemo16
description: try using template
spec:
type: openapi
lifecycle: experimental
owner: lab49-poc
definition:
$text: https://github.com/xxxx/stephendemo16/blob/master/src/main/resources/api-docs.yaml
This references the openapi spec api-docs.yaml
openapi: 3.0.1
info:
title: OpenAPI definition
version: v0
servers:
- url: http://localhost:8080
description: Generated server url
paths:
/greeting:
get:
tags:
- greeting-controller
operationId: greeting
parameters:
- name: name
in: query
required: false
schema:
type: string
default: World
responses:
"200":
description: OK
content:
'*/*':
schema:
$ref: '#/components/schemas/Greeting'
components:
schemas:
Greeting:
type: object
properties:
id:
type: integer
format: int64
content:
type: string
Why isn't the api registered when the component is created?
BTW Backstage is installed on AWS ECS.

Swagger, API Gateway using AWS Cloudformation

I am deploying a API which is mapped to a loadbalancer. I could test the API successfully on the console but while using the invoke link in the stage, I am getting a 403. The ELB is a http end point and the invoke url is https which is normal I would say.
Also if I use the ELB DNS Name, I could get the desired result. Looks like requests are not going through API Gateway.
I am doing all of this using Cloudformation and swagger. Here is the relevant part
EmployeeApi:
Type: AWS::ApiGateway::RestApi
Properties:
BodyS3Location:
Bucket: !Ref S3Bucket
Key: "swagger.yaml"
EmployeeApiDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref EmployeeApi
EmployeeApiStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId: !Ref EmployeeApiDeployment
RestApiId: !Ref EmployeeApi
StageName: dev
Variables:
employeeELB:
Fn::ImportValue:
!Sub ${NetworkStackName}-ELB
EmployeeApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: !Ref EmployeeApi
Stage: !Ref EmployeeApiStage
UsagePlanName: Basic
EmployeeApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: employee-api-key
Enabled: true
StageKeys:
- RestApiId: !Ref EmployeeApi
StageName: !Ref EmployeeApiStage
Relevant part of my swagger file is
swagger: "2.0"
info:
version: 1.0.0
title: employee-service
description: Welcome to API documentation of Employee Service
schemes:
- https
securityDefinitions:
api_key:
type: apiKey
name: x-api-key
in: header
x-amazon-apigateway-request-validators:
RequestValidator:
validateRequestBody: true
validateRequestParameters: true
x-amazon-apigateway-request-validator: RequestValidator
paths:
/employees:
get:
security:
- api_key: []
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
uri: http://${stageVariables.employeeELB}/employees
passthroughBehavior: when_no_match
httpMethod: GET
contentHandling: "CONVERT_TO_TEXT"
type: http_proxy

SAM give access to Cognito

I want to be able to call cognito functions through boto3 from my Lambda function in Python environment. What's the best way to give this type of access? I've done the following yaml but not sure if that's the best practice or I'm making the template longer.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Policies:
- AWSLambdaExecute # Managed Policy
- Version: '2012-10-17' # Policy Document
Statement:
- Effect: Allow
Action:
- cognito-idp:ListUsers
Resource: 'arn:aws:cognito-idp:us-east-2:****:*****'
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
I'm talking about the "Policies", is my template up to the standards? or is there a shortcut I can take?

AWS SAM template/cloudformation No integration defined for method (Service: AmazonApiGateway

I am trying to deploy a lambda function and API gateway . I create a .net core web API project with AWS CLI . Deploying only the function and creating the API gateway and resource manually on aws web console does work.
If I do include the API gateway in the template, after doing SAM package deploying through web console or CLI I get the following error:
"No integration defined for method (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: ....)"
Is anything wrong or missing here?
SAM package command:
sam package --template-file sam-profile.yaml --output-template-file serverless-output.yaml --s3-bucket testapp-fewtfvdy-lambda-deployments
SAM Template:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
ProfileFunction:
Type: AWS::Serverless::Function
Properties:
Handler: testapp.Profile.NetCoreVS::testapp.Profile.NetCoreVS.LambdaEntryPoint::FunctionHandlerAsync
Runtime: dotnetcore2.0
MemorySize : 128
Timeout : 5
CodeUri: bin/Release/netcoreapp2.0/publish
Events:
ProfileAny:
Type: Api
Properties:
RestApiId: !Ref ProfileApiGateway
Path: /profile/v1
Method: GET
ProfileApiGateway:
DependsOn: ProfileFunction
Type: 'AWS::Serverless::Api'
Properties:
StageName: Prod
DefinitionUri: './swagger.yaml'
swagger.yaml:
---
swagger: '2.0'
info:
version: v1
title: ProfileAPI
paths:
"/profile/v1":
get:
tags:
- Values
operationId: ProfileV1Get
consumes: []
produces:
- text/plain
- application/json
- text/json
parameters: []
responses:
'200':
description: Success
schema:
type: array
items:
type: string
definitions: {}
.net core method:
[Route("profile/v1")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2","value_new3" };
}
}
Your swagger definition is missing x-amazon-apigateway-integration.
This should provide that integration layer for you:
---
swagger: '2.0'
info:
version: v1
title: ProfileAPI
paths:
"/profile/v1":
get:
tags:
- Values
operationId: ProfileV1Get
consumes: []
produces:
- text/plain
- application/json
- text/json
parameters: []
responses:
'200':
description: Success
schema:
type: array
items:
type: string
x-amazon-apigateway-integration:
httpMethod: post
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProfileFunction.Arn}/invocations
definitions: {}
Note that the httpMethod for x-amazon-apigateway-integration is always POST, since API Gateway always makes POST requests to Lambda regardless of what method your API route is using.

How do I cloudform an API gateway resource with a lambda proxy integration

I've been trying to work out how to express (in cloudformation) an API Gateway Resource that has a Lambda function integration type using the Lambda Proxy integration.
This is easy to do in the AWS console as there is a check box that you can select:
However there is no corresponding field in the AWS::ApiGateway::Method CloudFormation resource (it should be in the Integration property).
How can I configure this in cloudformation?
The Integration type should be set to AWS_PROXY. An example snippet of a method from a working YAML CloudFormation template is below.
ProxyResourceAny:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: ANY
ResourceId:
Ref: ProxyResource
RestApiId:
Ref: API
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub
- arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Arn}/invocations
- Arn:
Fn::GetAtt:
- RestorerLambda
- Arn
It's worth saying how a I figured this out...
After scratching my head for a while I examined the output of the aws apigateway get-method CLI command for a method that was configured this way using the console. That gave me the following JSON and I realised that the checkbox might be encoded into the type. I tested my assumption and came up with the CloudFormation above.
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"methodIntegration": {
"integrationResponses": {
"200": {
"responseTemplates": {
"application/json": null
},
"statusCode": "200"
}
},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [],
"uri": "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:XXXXXXXXX:function:Shildrew-Restorer-Play-Lambda/invocations",
"httpMethod": "POST",
"cacheNamespace": "64bl3tgw4g",
"type": "AWS_PROXY"
},
"requestParameters": {},
"authorizationType": "NONE"
}
I have solved this same issue by simple changing the
Integration:
Type: AWS_PROXY
To
Integration:
Type: AWS
The cloud formation documentation currently is scarce and the API gateway cloudformation documentation doesn't match up to what can be seen on the console which hinders anyone who is trying to resolve an issue.
Hope this helps!
We faced this exact issue. We are using Ansible for our Infrastructure. Could apply to CLI or Cloudformation or even the SDK
The solution to our problem was to make sure that the Lambda policy was defined in a granular manner for the endpoint verbs in API Gateway for the lambda you are attempting to use.
For instance, We had multiple routes. Each route(or sets of routes) needs its own lambda policy defined that allows lambda:InvokeFunction. This is defined in the Lambda Policy module for Ansible. With this, the lambda trigger was enabled automatically.
There are two ways to achieve this:
Method 1: By defining the "Lambda", "API Gateway", "API Resource" and "API Methods". Linking the Lambda using the URI statement under "API Method".
MyLambdaFunction:
Type: "AWS::Lambda::Function"
Properties:
Description: "Node.js Express REST API"
FunctionName: "get_list_function" (The name in AWS console)
Handler: lambda.handler
Runtime: nodejs12
MemorySize: 128
Role: <ROLE ARN>
Timeout: 60
apiGateway:
Type: "AWS::ApiGateway::RestApi"
Properties:
Name: "example-api-gw"
Description: "Example API"
ProxyResource:
Type: "AWS::ApiGateway::Resource"
Properties:
ParentId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
PathPart: '{proxy+}' OR "a simple string like "PetStore"
apiGatewayRootMethod:
Type: "AWS::ApiGateway::Method"
Properties:
AuthorizationType: NONE
HttpMethod: ANY
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
IntegrationResponses:
- StatusCode: 200
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations
ResourceId: !Ref ProxyResource
RestApiId: !Ref "apiGateway"
METHOD 2: Define "API Gateway" and "Lambda". In Lambda definitions, call Events of type API.
CoreApi:
Type: 'AWS::Serverless::Api'
Properties:
StageName: dev
Name: SaaSAPI
EndpointConfiguration: Regional
Cors:
AllowMethods: '''POST, GET, OPTIONS, PATCH, DELETE, PUT'''
AllowHeaders: '''Content-Type, X-Amz-Date, Authorization, X-Api-Key, x-requested-with'''
AllowOrigin: '''*'''
MaxAge: '''600'''
MyLambdaFunction:
Type: "AWS::Lambda::Function"
Properties:
Description: "Node.js Express REST API"
FunctionName: "get_list_function"
Handler: lambda.handler
Runtime: nodejs12
MemorySize: 128
Role: <ROLE ARN>
Timeout: 60
Events:
ProxyResourceA:
Type: Api
Properties:
Path: /Departments
Method: GET
RestApiId: !Ref CoreApi
ProxyResourceB:
Type: Api
Properties:
Path: /Departments (This becomes the resource in API Gateway)
Method: POST
RestApiId: !Ref CoreApi
(You can link multiple methods with the same lambda, provide a unique name to each event, like ProxyResoruceA & ProxyResourceB)

Resources