CloudFormation to Configure API Gateway Method to use Cognito Authorizer - aws-api-gateway

I'm trying to define API Gateway resources using CloudFormation. Specifically, I'm attempting to create a template for an API Gateway Resource Method that authenticates using Cognito. I've created the Authorizer, and using the console I can perform this configuration without issue (see image attached). I just can't find a way to specify the API method request authorization using the Cognito user pool. It's driving me crazy. As far as I can see, no documentation covers this.
Does anyone know if this is possible, and if so, how to do it? I realize I can achieve this using Swagger but I'm not looking forward to re-defining all of my API Gateway resources in Swagger vs. CloudFormation.
Thanks in advance!

If you are using SAM then you set the pool as a global default and mark the functions you don't want to be authenticated.
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Cors: "'*'"
Auth:
DefaultAuthorizer: MyCognitoAuthorizer
Authorizers:
MyCognitoAuthorizer:
UserPoolArn: !GetAtt MyCognitoUserPool.Arn
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./src
Handler: lambda.handler
Runtime: nodejs8.10
Events:
Root:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /
Method: GET
MyCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Ref CognitoUserPoolName
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: email
Required: false
MyCognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref MyCognitoUserPool
ClientName: !Ref CognitoUserPoolClientName
GenerateSecret: false
For functions you don't want to be behind cognito. Define in the events section of the AWS::Serverless::Function definition.
Events:
Root:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /
Method: GET
Auth:
Authorizer: 'NONE'
Use the AWS Sam template documentation rather than the cloudformation definitions.

I don't have a code sample handy, but here's what you will need to do:
1) Add an Authorizer resource to your template with type "COGNITO_USER_POOLS",
2) Set the authorizerId on the API method resource to the ID reference from the authorizer. Set the authorizationType on the method to "COGNITO_USER_POOLS"
As for the user pools themselves, you will need to use custom resources, at least until official support is released. There are several open-source implementations out there that you could use (here's one example: https://github.com/aws-samples/aws-api-gateway-developer-portal/tree/7d0d1e56d54e9775ee2d18907ebdf1db9dafcc06/lambdas/cognito-cloudformation-custom-resource)

Related

Google API Gateway OpenApi Swaagger 2.0 to CloudRun Parameter configured for Path turns out in query instead of path

I'm testing an API Gateway setup on Google Cloud to access specific endpoints on a service deployed on Cloud Run. I'm following the steps shown here. We need to authenticate using an API Key, so the API Key specific configuration that went into the API Gateway config was picked from this documentation.
The API Gateway config is as shown below:
# api_gateway_config.yaml
swagger: '2.0'
info:
title: myappapi
description: API with Cloudrun Backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/:
get:
summary: Greet a User from service
operationId: hello
x-google-backend:
address: https://myappapi-asldfjoiewjfv-uc.a.run.app/
security:
- api_key: []
responses:
'200':
description: A successful response
schema:
type: string
/reports/results/{id}:
get:
summary: Get Report Results for specified report id
operationId: GetReportResults
x-google-backend:
address: https://myappapi-asldfjoiewjfv-uc.a.run.app/v1/reports/results/{id}
parameters:
- in: path
name: id
required: true
type: integer
security:
- api_key: []
responses:
'200':
description: A successful response
schema:
type: string
securityDefinitions:
# This section configures basic authentication with an API Key.
api_key:
type: "apiKey"
name: "key"
in: "query"
For a sample call to the /reports/results endpoint as http://myappapi/reports/results/1,
the expectation is for calls to get converted to https://myappapi-asldfjoiewjfv-uc.a.run.app/v1/reports/results/1?key=MyAPIKeyHere. But instead they turn out as https://myappapi-asldfjoiewjfv-uc.a.run.app/v1/reports/results?key=MyAPIKeyHere&id=1
Is there a way to get the API calls go as https://myappapi-asldfjoiewjfv-uc.a.run.app/v1/reports/results/1?key=MyAPIKeyHere ?
Thanks in Advance!
As mentioned in this documentation
Set path_translation as part of setting x-google-backend:
x-google-backend:
address: https://GCP_REGION-PROJECT_ID.cloudfunctions.net/hello
path_translation: [ APPEND_PATH_TO_ADDRESS | CONSTANT_ADDRESS ]
The default value of path_translation depends on where you set x-google->backend in your OpenAPI spec:
When x-google-backend is used at the top level of the OpenAPI specification, path_translation defaults to APPEND_PATH_TO_ADDRESS.
When x-google-backend is used at the operation level of the OpenAPI specification, path_translation defaults to CONSTANT_ADDRESS.
For more details on path translation, please see the Understanding path translation section. You can also check this stackoverflow thread.

AWS ApiGateaway Cloudformation: I have a problem with JWTConfiguration when creating the authorizer

Creating a Gateaway API via AWS Cloudformation I have a problem with JWTConfiguration when creating the authorizer.
Authorizer:
Type: 'AWS::ApiGatewayV2::Authorizer'
Properties:
Name: VSTORES_Api_CognitoAuthorizer
ApiId: !Ref VCloudApiGateway
AuthorizerType: JWT
IdentitySource:
- '$request.header.Authorization'
AuthorizerResultTtlInSeconds: 3600
JWTConfiguration:
Audience:
- xxxxxxxxxxxxxxxxxxxxx
Issuer: https://cognito-idp.us-east-1.amazonaws.com/us-east-xxxxxxx
I get the following error:
Property validation failure: [Encountered unsupported properties in
{/}: [JWTConfiguration]]
what am I doing wrong?
Judging by the documentation it looks like your formatting is correct. I suggest ensuring your JWT value is compliant with RFC 7519 and able to be decoded using a website similar to https://jwt.io/

Getting cors error when api gateway deployed using SAM template

I have developed lambda functions in node.js and trying to deploy to api gateway with proxy integration using SAM templates.
my lambda functions are returning headers as mentioned in AWS documentation
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "https://www.example.com",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
template.yaml code
GetClientFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/GetClient/
Handler: index.handler
Runtime: nodejs14.x
Events:
GetClientCustomFieldMap:
Type: Api
Properties:
RestApiId: !Ref ClientApi # this is api with authorizer configured
Path: api/Client/GetClient/{name}
Method: get
It is creating all resources which mentioned in the path like 'api', 'Client', 'GetClient' but not with Options method, also getting cors error. Tried multiple ways from stackoverflow but could not resolve it.
Followed this url as well How to enable CORS with AWS SAM
You need to configure Cors of the Api resource for the OPTIONS methods, see https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-cors

Cloudformation: Reference created ACM Certificate in other region

Since https certificates for Cloudfront can only be created in us-east-1 and my entire stack is created in eu-west-1 I wanted to create a stack in us-east-1 that contains the ACM certificate, and then use that certificate in my stack(s) in eu-west-1.
The only problem is, how do I reference this certificate without hardcoding it, as I can't ImportValue an output in another region.
e.g.
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.RegionalDomainName
Id: ****
CustomOriginConfig:
HTTPPort: '80'
HTTPSPort: '443'
OriginProtocolPolicy: https-only
DefaultRootObject: 'index.html'
Enabled: true
Aliases:
- 'bla.bla.com'
DefaultCacheBehavior:
TargetOriginId: '*-origin'
AllowedMethods:
- GET
- HEAD
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6'
ViewerCertificate:
AcmCertificateArn: !ImportValue ****
SslSupportMethod: sni-only
What do I need to put on the AcmCertificateArn line when I deploy this in eu-west-1?
As you've pointed out, you can't make cross-region export/import references between stacks in different regions. In this case, usually you would provide the Certificate ARN as an input parameter to your stack in eu-west-1.
The other options would involve the use of SSM parameters dynamic references to pass the value of the certificate's ARN. For fully automated solution, you would need to develop a custom resource in eu-west-1 in the form of a lambda function. The function would query the stack in us-east-1 for the arn in its outputs and return the arn to the stack in eu-west-1.

How to setup Oauth scopes at AWS Serverless Function?

Issue: OAuth Scopes are empty at Method Request Settings using Cloudformation and AWS-SAM
Apparently there are a few places where I can declare my authorization scopes, if I got it right, I should declare all scopes at the authorizer and the ones I would like to specify per function at my Function template.
This is the template I am trying to fix:
MyServerlessFn
Type: AWS::Serverless::Function
Properties:
FunctionName: helloWorldFn
Description: my test using cognito.
Handler: src/handlers/helloWorld.handler
Runtime: nodejs12.x
Events:
ApplicationPostAPI:
Type: Api
Properties:
Auth:
AuthorizationScopes:
- https://foobar.acme.net/full-api
Method: POST
Path: /hello/world
RestApiId: !Ref MyServerlessApi
using sam cli I can validate, build and deploy this template but the oauthScopes are empty when I check it using AWS web console.
Here the aws doc:
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-apifunctionauth.html
I also noticed that the scopes you define on a function level stay empty.
Whether the documentation is wrong or a current AWS SAM bug I leave in the midle.
(see: https://github.com/aws/serverless-application-model/issues/1752)
However you can solve this by specifying an authorizer on the api level and refer to this authorizer on function level.
ApiGw:
Type: AWS::Serverless::Api
Properties:
Description: some description
Auth:
Authorizers:
DefaultAuthorizer:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizerWithScopeABC:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizationScopes:
- /ABC
AuthorizerWithScopeXYZ:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizationScopes:
- /XYZ
DefaultAuthorizer: DefaultAuthorizer
Function:
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Type: Api
Properties:
Path: /somepath
Method: get
RestApiId: !Ref ApiGw
Auth:
Authorizer: AuthorizerWithScopeABC