I want to use the standard API Keys feature of API Gateway. If I use standard cloudformation this is possible by setting the property ApiKeyRequired to true for a method. How can I do this with SAM?
I tried using swagger but that does not seem to work:
swagger: "2.0"
info:
title: !Ref AWS::StackName
paths:
"/machines/{resourceid}":
get:
parameters:
- name: resourceid
in: path
type: string
required: true
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambda.Arn}/invocations
responses: {}
security:
- authorizer: []
securityDefinitions:
authorizer:
type: apiKey
name: Authorization
in: header
Any suggestions?
The following swagger definition works:
DefinitionBody:
swagger: "2.0"
info:
title: !Ref AWS::StackName
x-amazon-apigateway-api-key-source : "HEADER"
paths:
"/machines/{resourceId}":
get:
parameters:
- name: resourceId
in: path
type: string
required: true
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MessagingServiceTestHandler.Arn}/invocations
responses: {}
security:
- api_key: []
securityDefinitions:
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
The name of the api key header must be x-api-key rather than the standard Authorization header.
Related
I'm trying to get API Gateway to do the above. See template at the bottom - there is a single message parameter, which I've tried to restrict to either foo or bar values, via specification of an AWS::ApiGateway::Model resource, bound to Content-Type application/x-www-form-urlencoded.
Now APIGW will validate the presence of the message parameter -
curl -H "Content-Type: application/x-www-form-urlencoded" "https://xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/1-0-0/hello?messag=foo"
{"message": "Missing required request parameters: [message]"}
But it doesn't seem to validate or restrict the value sent -
curl -H "Content-Type: application/x-www-form-urlencoded" "https://xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/1-0-0/hello?message=whatever"
you sent 'whatever'
Any idea what I am doing wrong here?
AWSTemplateFormatVersion: '2010-09-09'
Outputs:
PublicApiEndpoint:
Value:
Fn::Sub: https://${PublicApiRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${PublicApiStage}
Parameters:
MemorySizeDefault:
Default: '512'
Type: String
RuntimeVersion:
Default: '3.8'
Type: String
TimeoutDefault:
Default: '5'
Type: String
Resources:
HelloFunction:
Properties:
Code:
ZipFile: |
def handler(event, context):
message=event["queryStringParameters"]["message"]
response="you sent '%s'" % message
return {'statusCode': 200,
'headers': {"Content-Type": "text/plain"},
'body': response}
Handler: index.handler
MemorySize:
Ref: MemorySizeDefault
Role:
Fn::GetAtt:
- HelloFunctionRole
- Arn
Runtime:
Fn::Sub: python${RuntimeVersion}
Timeout:
Ref: TimeoutDefault
Type: AWS::Lambda::Function
HelloFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: '2012-10-17'
Policies:
- PolicyDocument:
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Effect: Allow
Resource: '*'
Version: '2012-10-17'
PolicyName:
Fn::Sub: hello-function-role-policy-${AWS::StackName}
Type: AWS::IAM::Role
HelloEndpointMethod:
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri:
Fn::Sub:
- arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations
- arn:
Fn::GetAtt:
- HelloFunction
- Arn
RequestParameters:
"method.request.querystring.message": true
RequestValidatorId:
Ref: HelloEndpointValidator
RequestModels:
"application/x-www-form-urlencoded": HelloEndpointModel
ResourceId:
Ref: HelloEndpointResource
RestApiId:
Ref: PublicApiRestApi
Type: AWS::ApiGateway::Method
HelloEndpointPermission:
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: HelloFunction
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PublicApiRestApi}/${PublicApiStage}/GET/hello
Type: AWS::Lambda::Permission
HelloEndpointResource:
Properties:
ParentId:
Fn::GetAtt:
- PublicApiRestApi
- RootResourceId
PathPart: hello
RestApiId:
Ref: PublicApiRestApi
Type: AWS::ApiGateway::Resource
HelloEndpointValidator:
Properties:
RestApiId:
Ref: PublicApiRestApi
ValidateRequestParameters: true
Type: AWS::ApiGateway::RequestValidator
HelloEndpointModel:
Properties:
RestApiId:
Ref: PublicApiRestApi
ContentType: 'application/x-www-form-urlencoded'
Name: HelloEndpointModel
Schema:
"$schema": "http://json-schema.org/draft-04/schema#"
type: object
properties:
message:
type: string
pattern: "^((foo)|(bar))$"
required:
- message
Type: AWS::ApiGateway::Model
PublicApiDeployment:
DependsOn:
- HelloEndpointMethod
Properties:
RestApiId:
Ref: PublicApiRestApi
Type: AWS::ApiGateway::Deployment
PublicApiRestApi:
Properties:
Name:
Fn::Sub: public-api-rest-api-${AWS::StackName}
Type: AWS::ApiGateway::RestApi
PublicApiStage:
Properties:
DeploymentId:
Ref: PublicApiDeployment
RestApiId:
Ref: PublicApiRestApi
StageName: 1-0-0
Type: AWS::ApiGateway::Stage
Apparently this is not possible - https://twitter.com/alexbdebrie/status/1603059764489252864?s=20&t=LI7OUEw9b5qxCIvkeP4AYQ
i’m trying to add proxy to my lambda function, but i’m getting error:
“CREATE_FAILED: ApiGatewayResourceJokes (AWS::ApiGateway::Resource)
Resource handler returned message: “Another resource with the same
parent already has this name: example (Service: ApiGateway, Status
Code: 409, Request ID: 3fb2a85c-6fd2-4414-ad3f-72ee095da48b)”
(RequestToken: f33a6da3-be94-9696-3fd6-35a7bc52ef0a, HandlerErrorCode:
AlreadyExists)”
example:
handler: lambdas/endpoints/proxy.handler
events:
- http: GET /example
ProxyResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Fn::GetAtt:
- ApiGatewayRestApi # our default Rest API logical ID
- RootResourceId
PathPart: jokes # the endpoint in your API that is set as proxy
RestApiId:
Ref: ApiGatewayRestApi
ProxyMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: ProxyResource
RestApiId:
Ref: ApiGatewayRestApi
HttpMethod: GET # the method of your proxy. Is it GET or POST or ... ?
MethodResponses:
- StatusCode: 200
Integration:
IntegrationHttpMethod: POST
Type: HTTP
Uri: http://api.icndb.com/jokes/random # the URL you want to set a proxy to
IntegrationResponses:
- StatusCode: 200
Edit: This started working as expected by itself the day after. I'm very sure I didn't do anything different. Don't know what to do with the question. Close, Delete?, Let it be?
I am creating a servless web api using AWS SAM and the new HTTP API gateway.
This is my current template file:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
fotffleet-api
Sample SAM Template for fotffleet-api
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
CodeUri: fotffleet/
Runtime: python3.7
Resources:
ServerlessHttpApi:
Type: AWS::Serverless::HttpApi
Properties:
CorsConfiguration:
AllowOrigins:
- "http://localhost:3000"
AllowMethods:
- GET
DefinitionBody:
openapi: "3.0.1"
info:
title: "sam-app"
version: "1.0"
tags:
- name: "httpapi:createdBy"
x-amazon-apigateway-tag-value: "SAM"
paths:
/cells:
get:
responses:
default:
description: "Default response for GET /cells"
x-amazon-apigateway-integration:
payloadFormatVersion: "2.0"
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::GetAtt: [CellsFunction, Arn]
connectionType: "INTERNET"
/cells/{cellName}:
get:
responses:
default:
description: "Default response for GET /cells/{cellName}"
x-amazon-apigateway-integration:
payloadFormatVersion: "2.0"
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::GetAtt: [CellInfoFunction, Arn]
connectionType: "INTERNET"
/hello:
get:
responses:
default:
description: "Default response for GET /hello"
x-amazon-apigateway-integration:
payloadFormatVersion: "2.0"
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::GetAtt: [HelloFunction, Arn]
connectionType: "INTERNET"
/jobs/{cellName}:
get:
responses:
default:
description: "Default response for GET /jobs/{cellName}"
x-amazon-apigateway-integration:
payloadFormatVersion: "2.0"
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::GetAtt: [JobsFunction, Arn]
connectionType: "INTERNET"
x-amazon-apigateway-cors:
maxAge: 0
allowCredentials: false
allowOrigins:
- "http://localhost:3000"
x-amazon-apigateway-importexport-version: "1.0"
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.hello
Events:
Hello:
Type: HttpApi
Properties:
Path: /hello
Method: get
ApiId: !Ref ServerlessHttpApi
CellInfoFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.cell_info
Policies:
- AWSIoTFullAccess
Events:
Http:
Type: HttpApi
Properties:
Path: /cells/{cellName}
Method: get
ApiId: !Ref ServerlessHttpApi
CellsFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.cells
Policies:
- AWSIoTFullAccess
Events:
Http:
Type: HttpApi
Properties:
Path: /cells
Method: get
ApiId: !Ref ServerlessHttpApi
JobsFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.jobs
Policies:
- AmazonDynamoDBReadOnlyAccess
Events:
Http:
Type: HttpApi
Properties:
Path: /jobs/{cellName}
Method: get
ApiId: !Ref ServerlessHttpApi
Outputs:
# 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"
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
As it can be seen, I have added some CORS configuration. Both in the AWS::Serverless::HttpApi and also in the DefinitionBody i.e. the OpenAPI spec.
My problem is that as far as I can tell, all CORS configurations are completely ignored. When I deploy after changing cors configuration, it says:
Waiting for changeset to be created..
Error: No changes to deploy. Stack sam-app is up to date
When I run sam validate --debug --profile [my-profile] it is my understandign that the CloudFormation file which it tries to deploy is output. It looks like this:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'fotffleet-api
Sample SAM Template for fotffleet-api
'
Resources:
HelloFunction:
Properties:
Code:
S3Bucket: bucket
S3Key: value
Handler: app.hello
Role:
Fn::GetAtt:
- HelloFunctionRole
- Arn
Runtime: python3.7
Tags:
- Key: lambda:createdBy
Value: SAM
Timeout: 3
Type: AWS::Lambda::Function
HelloFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Tags:
- Key: lambda:createdBy
Value: SAM
Type: AWS::IAM::Role
HelloFunctionHelloPermission:
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: HelloFunction
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Sub:
- arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello
- __ApiId__:
Ref: ServerlessHttpApi
__Stage__: '*'
Type: AWS::Lambda::Permission
CellInfoFunction:
Properties:
Code:
S3Bucket: bucket
S3Key: value
Handler: app.cell_info
Role:
Fn::GetAtt:
- CellInfoFunctionRole
- Arn
Runtime: python3.7
Tags:
- Key: lambda:createdBy
Value: SAM
Timeout: 3
Type: AWS::Lambda::Function
CellInfoFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AWSIoTFullAccess
Tags:
- Key: lambda:createdBy
Value: SAM
Type: AWS::IAM::Role
CellInfoFunctionHttpPermission:
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: CellInfoFunction
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Sub:
- arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/cells/*
- __ApiId__:
Ref: ServerlessHttpApi
__Stage__: '*'
Type: AWS::Lambda::Permission
CellsFunction:
Properties:
Code:
S3Bucket: bucket
S3Key: value
Handler: app.cells
Role:
Fn::GetAtt:
- CellsFunctionRole
- Arn
Runtime: python3.7
Tags:
- Key: lambda:createdBy
Value: SAM
Timeout: 3
Type: AWS::Lambda::Function
CellsFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AWSIoTFullAccess
Tags:
- Key: lambda:createdBy
Value: SAM
Type: AWS::IAM::Role
CellsFunctionHttpPermission:
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: CellsFunction
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Sub:
- arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/cells
- __ApiId__:
Ref: ServerlessHttpApi
__Stage__: '*'
Type: AWS::Lambda::Permission
JobsFunction:
Properties:
Code:
S3Bucket: bucket
S3Key: value
Handler: app.jobs
Role:
Fn::GetAtt:
- JobsFunctionRole
- Arn
Runtime: python3.7
Tags:
- Key: lambda:createdBy
Value: SAM
Timeout: 3
Type: AWS::Lambda::Function
JobsFunctionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess
Tags:
- Key: lambda:createdBy
Value: SAM
Type: AWS::IAM::Role
JobsFunctionHttpPermission:
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: JobsFunction
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Sub:
- arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/jobs/*
- __ApiId__:
Ref: ServerlessHttpApi
__Stage__: '*'
Type: AWS::Lambda::Permission
ServerlessHttpApi:
Properties:
Body:
info:
title:
Ref: AWS::StackName
version: '1.0'
openapi: 3.0.1
paths:
/cells:
get:
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
payloadFormatVersion: '2.0'
type: aws_proxy
uri:
Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CellsFunction.Arn}/invocations
/cells/{cellName}:
get:
parameters:
- in: path
name: cellName
required: true
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
payloadFormatVersion: '2.0'
type: aws_proxy
uri:
Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CellInfoFunction.Arn}/invocations
/hello:
get:
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
payloadFormatVersion: '2.0'
type: aws_proxy
uri:
Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloFunction.Arn}/invocations
/jobs/{cellName}:
get:
parameters:
- in: path
name: cellName
required: true
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
payloadFormatVersion: '2.0'
type: aws_proxy
uri:
Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${JobsFunction.Arn}/invocations
tags:
- name: httpapi:createdBy
x-amazon-apigateway-tag-value: SAM
Type: AWS::ApiGatewayV2::Api
ServerlessHttpApiApiGatewayDefaultStage:
Properties:
ApiId:
Ref: ServerlessHttpApi
AutoDeploy: true
StageName: $default
Tags:
httpapi:createdBy: SAM
Type: AWS::ApiGatewayV2::Stage
Outputs:
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage
Value:
Fn::Sub: https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com
I don't know what this should look like, but I find it strange that there is no mention of anything CORS related in there at all.
I have tried many variations such as: CORS settings only in the properites, only in the openAPI definition, not having a definition body and letting SAM generate it, having it in a seperate file.
No matter what I do, it is as if SAM completely and silently ignores any cors settings.
If it is not obvious, I would like to know what to do in order to get SAM to apply these CORS settings on deploy.
I am trying to configure an API Gateway which takes a proxy parameter from the request path, and also a parameter from the Lambda authorizer return and put it in the header, so that it can be passed to my Elastic Beanstalk REST API running Spring Boot.
The proxy path is working as expected; and I see my Lambda function is returning the variable "x-api-auth" in the "context" map as per documentation.
The only piece not working is adding "x-api-auth" to the request header. :( Whenever I ran my Jenkins build to update the Cloudformation stack, I get this error:
Errors found during import: Unable to put integration on 'ANY' for resource at path '/sfdc/v1/feature-api/{proxy+}': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: $context.authorizer.x-api-auth] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException
It is super frustrating and I've double checked OpenAPI documentation to make sure my syntax is correct. Any help or tips would be most appreciated!
Here is the Cloudformation template I have:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Data API pipeline initial Cloudformation template
Mappings:
EnvironmentMapping:
alpha:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: XYZ
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
beta:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: XYZ
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
prod:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: ABC
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
Parameters:
EnvironmentType:
Type: "String"
AllowedValues:
- alpha
- beta
- prod
Conditions:
UseProdCondition: !Equals [!Ref EnvironmentType, prod]
Resources:
MyApiVpcLink:
Type: AWS::ApiGateway::VpcLink
Properties:
Name: MyApiVpcLink
Description: Allows data-api-gateway to access the VPC that my-api is on.
TargetArns:
- !FindInMap [EnvironmentMapping, !Ref EnvironmentType, myApiNetworkLoadBalancer]
DataApi:
DependsOn:
- MyApiVpcLink
Type: AWS::Serverless::Api
Properties:
Name: !Sub "${EnvironmentType}-data-api"
StageName: !Ref EnvironmentType
DefinitionBody:
swagger: 2.0
security:
- ApiKey: []
info:
title: !Sub "${EnvironmentType}-data-api"
paths:
/sfdc/v1/my-api/{proxy+}:
x-amazon-apigateway-any-method:
produces:
- application/json
parameters:
- in: path
name: proxy
required: true
schema:
type: string
- in: header
name: x-api-auth
required: true
schema:
type: string
security:
- SfdcAuthorizer: []
ApiKey: []
x-amazon-apigateway-api-key-source: HEADER
x-amazon-apigateway-gateway-responses:
ACCESS_DENIED:
statusCode: 403
responseTemplates:
application/json: '{\n\"message\": \"Access Denied\"}'
x-amazon-apigateway-integration:
httpMethod: ANY
type: http_proxy
connectionType: VPC_LINK
connectionId: !Ref MyApiVpcLink
passthroughBehavior: when_no_match
uri: !If [UseProdCondition, 'http://myapp.production.aws-int.myorg.io/{proxy}',!Sub 'http://${EnvironmentType}-myapp.staging.aws-int.myorg.io/{proxy}']
requestParameters:
integration.request.path.proxy: "method.request.path.proxy"
# -------------------- this breaks it once added -------------------
integration.request.header.x-api-auth: "$context.authorizer.x-api-auth"
# ------------------------------------------------------------------
definitions:
Empty:
type: object
Error:
type: object
properties:
message:
type: string
securityDefinitions:
SfdcAuthorizer:
type: 'apiKey'
name: 'Authorization'
in: 'header'
x-amazon-apigateway-authtype: 'custom'
x-amazon-apigateway-authorizer:
authorizerUri: !Join ['', [!Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/', !FindInMap [EnvironmentMapping, !Ref EnvironmentType, sfdcAuthLambda], '/invocations']]
authorizerResultTtlInSeconds: !FindInMap [EnvironmentMapping, !Ref EnvironmentType, sfdcAuthTimeout]
type: 'token'
ApiKey:
type: apiKey
name: x-api-key
in: header
Well... after getting nowhere with following the documentation, I went rogue and removed the "$" from "integration.request.header.x-api-auth"... AND THAT WORKED. Not sure how I feel about this.
Here is the complete working YAML file. I'm posting it here in case it should help someone else who is trying to set up a gateway which takes PROXY path and expects a return from a Lambda authorizer.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Data API pipeline initial Cloudformation template
Mappings:
EnvironmentMapping:
alpha:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: XYZ
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
beta:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: XYZ
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
prod:
certificationArn: ""
carfaxIpWhitelistRuleId: ""
hostedZoneId: ABC
authLambda: ""
sfdcAuthLambda: ""
myApiNetworkLoadBalancer: ""
sfdcAuthTimeout: 1
Parameters:
EnvironmentType:
Type: "String"
AllowedValues:
- alpha
- beta
- prod
Conditions:
UseProdCondition: !Equals [!Ref EnvironmentType, prod]
Resources:
MyApiVpcLink:
Type: AWS::ApiGateway::VpcLink
Properties:
Name: MYApiVpcLink
Description: Allows data-api-gateway to access the VPC that feature-api is on.
TargetArns:
- !FindInMap [EnvironmentMapping, !Ref EnvironmentType, myApiNetworkLoadBalancer]
DataApi:
DependsOn:
- MyApiVpcLink
Type: AWS::Serverless::Api
Properties:
Name: !Sub "${EnvironmentType}-data-api"
StageName: !Ref EnvironmentType
DefinitionBody:
swagger: 2.0
security:
- ApiKey: []
info:
title: !Sub "${EnvironmentType}-data-api"
paths:
/sfdc/v1/my-api/{proxy+}:
x-amazon-apigateway-any-method:
produces:
- application/json
parameters:
- in: path
name: proxy
required: true
schema:
type: string
- in: header
name: x-api-auth
required: true
schema:
type: string
security:
- SfdcAuthorizer: []
ApiKey: []
x-amazon-apigateway-api-key-source: HEADER
x-amazon-apigateway-gateway-responses:
ACCESS_DENIED:
statusCode: 403
responseTemplates:
application/json: '{\n\"message\": \"Access Denied\"}'
x-amazon-apigateway-integration:
httpMethod: ANY
type: http_proxy
connectionType: VPC_LINK
connectionId: !Ref MyApiVpcLink
passthroughBehavior: when_no_match
uri: !If [UseProdCondition, 'http://myapp.production.aws-int.myorg.io/{proxy}',!Sub 'http://${EnvironmentType}-myapp.staging.aws-int.myorg.io/{proxy}']
requestParameters:
integration.request.path.proxy: "method.request.path.proxy"
integration.request.header.x-api-auth: "context.authorizer.x-api-auth"
definitions:
Empty:
type: object
Error:
type: object
properties:
message:
type: string
securityDefinitions:
SfdcAuthorizer:
type: 'apiKey'
name: 'Authorization'
in: 'header'
x-amazon-apigateway-authtype: 'custom'
x-amazon-apigateway-authorizer:
authorizerUri: !Join ['', [!Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/', !FindInMap [EnvironmentMapping, !Ref EnvironmentType, sfdcAuthLambda], '/invocations']]
authorizerResultTtlInSeconds: !FindInMap [EnvironmentMapping, !Ref EnvironmentType, sfdcAuthTimeout]
type: 'token'
ApiKey:
type: apiKey
name: x-api-key
in: header
How do I create methods under API Gateway's root / folder using CF? So for example I have a Gateway that looks like the following:
/
OPTIONS
POST
However when trying to do that with CF I get:
Resource's path part only allow a-zA-Z0-9._- and curly braces at the beginning and the end. So my PathPart is the offending line.
ApiGate:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt
- ApiGateApi
- RootResourceId
PathPart: '{/}'
RestApiId: !Ref ApiGateApi
I can change the PathPart to something else but then it creates it as a child object under / which is what I don't want.
Turns out after adding the following to my AWS::ApiGateway::Method it works now.
MyMethodOPTIONS:
Type: 'AWS::ApiGateway::Method'
Properties:
ResourceId: !GetAtt MyRestApi.RootResourceId
Here is more context into my Template:
ApiGatewayMethodOPTIONS:
Type: 'AWS::ApiGateway::Method'
Properties:
ResourceId: !GetAtt ApiGatewayRestApi.RootResourceId
RestApiId: !Ref ApiGatewayRestApi
AuthorizationType: NONE
HttpMethod: OPTIONS
Integration:
Type: MOCK
IntegrationResponses:
- ResponseParameters:
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
method.response.header.Access-Control-Allow-Methods: "'POST,OPTIONS'"
method.response.header.Access-Control-Allow-Origin: "'*'"
ResponseTemplates:
application/json: ''
StatusCode: '200'
PassthroughBehavior: NEVER
RequestTemplates:
application/json: '{"statusCode": 200}'
MethodResponses:
- ResponseModels:
application/json: Empty
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Origin: true
StatusCode: '200'
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
ApiKeySourceType: HEADER
EndpointConfiguration:
Types:
- REGIONAL
Name: SearchAPI
This fixes my problem, in my case I needed to have 2 methods:
1. will respond to requests to root e.g. https://<api-url>/prod or https://<api-url>/prod/. This will use the RootResourceId of the API Gateway:
ResourceId: !GetAtt myApiGateway.RootResourceId
this will respond to requests to whatever has been set under https://<api-url>/prod/. Could be petstore or if using {proxy+} then the backend workload will try to resolve the request. It will refer to the Resource type defined in the template:
ResourceId: !Ref myResource