Description
Ensure that every Amazon API Gateway HTTP or WebSocket API (API Gateway V2) has at least one authorizer defined to authenticate requests. An authorizer, either a JWT authorizer (for example with Amazon Cognito) or a Lambda authorizer, checks the caller's token or request details before the route is invoked. Only the existence of an authorizer on the API is evaluated; whether the routes actually reference the authorizer is not verified.
Rationale
Without an authorizer, anyone who knows the API endpoint can invoke its routes. This can expose data, allow unauthorized changes and let automated abuse drive up backend load and costs. Using an authorizer ensures that only authenticated callers can use the API, and scopes, claims or policy decisions can further limit what each caller is allowed to do. Resource policies, throttling and AWS WAF add further layers of protection.
Impact
Prevents unauthenticated access to API routes and their backends
Allows access to be limited to specific users, applications or scopes
Existing clients must send a valid token or credentials once the authorizer is attached to their routes, otherwise their requests are rejected
Lambda authorizers add latency and Lambda invocation costs
Default Value
New HTTP and WebSocket APIs have no authorizers, and their routes are created with authorization type NONE.
Pre-Requisites
IAM permissions: apigateway:GET, apigateway:POST, apigateway:PATCH and apigateway:DELETE on the API, plus lambda:AddPermission when using a Lambda authorizer
For a JWT authorizer (HTTP APIs only): the token issuer URL and audience, for example from an Amazon Cognito user pool
For a Lambda authorizer: a Lambda function that validates the request and returns the authorization decision
A plan for updating API clients to send the required token or credentials
Remediation
Test Plan
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the API Gateway console and select an HTTP or WebSocket API.
Open the authorization or Authorizers page of the API and check whether any authorizer exists.
Repeat for each API in each region in use.
If the API has no authorizer, follow the implementation steps.
CLI:
List the HTTP and WebSocket APIs:
aws apigatewayv2 get-apis --region <REGION> --query "Items[].[ApiId,Name,ProtocolType]" --output table
List the authorizers of an API:
aws apigatewayv2 get-authorizers --region <REGION> --api-id <API_ID> --query "Items[].[AuthorizerId,Name,AuthorizerType]" --output table
Show which routes use an authorizer, because an authorizer only protects the routes it is attached to:
aws apigatewayv2 get-routes --region <REGION> --api-id <API_ID> --query "Items[].[RouteKey,AuthorizationType,AuthorizerId]" --output table
The API fails only if it has no authorizers at all; an API with a defined authorizer passes even if no route references it. Routes with authorization type NONE should therefore also be reviewed, even if the API has an authorizer.
Implementation Steps
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the API Gateway console and select the HTTP or WebSocket API.
Open the authorization or Authorizers page and create an authorizer:
for a JWT authorizer, enter the identity source (for example $request.header.Authorization), the issuer URL and the audience,
for a Lambda authorizer, select the Lambda function and the identity source, and allow API Gateway to invoke the function.
Attach the authorizer to each route that requires authentication (for WebSocket APIs, to the $connect route).
Deploy the API if the stage does not use automatic deployment.
Repeat for each affected API in each region in use.
CLI:
Create a Lambda authorizer for an HTTP API. The payload format version is required for Lambda authorizers on HTTP APIs, so it is added here:
aws apigatewayv2 create-authorizer --region <REGION> --api-id <API_ID> --authorizer-type REQUEST --name <AUTHORIZER_NAME> --authorizer-uri arn:aws:apigateway:<REGION>:lambda:path/2015-03-31/functions/<LAMBDA_FUNCTION_ARN>/invocations --identity-source '$request.header.Authorization' --authorizer-payload-format-version 2.0 --enable-simple-responses
Allow API Gateway to invoke the authorizer function:
aws lambda add-permission --region <REGION> --function-name <LAMBDA_FUNCTION_NAME> --statement-id apigateway-authorizer --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn arn:aws:execute-api:<REGION>:<ACCOUNT_ID>:<API_ID>/authorizers/<AUTHORIZER_ID>
Attach the authorizer to a route:
aws apigatewayv2 update-route --region <REGION> --api-id <API_ID> --route-id <ROUTE_ID> --authorization-type CUSTOM --authorizer-id <AUTHORIZER_ID>
Backout Plan
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the API Gateway console and select the API.
Detach the authorizer from each route it was attached to.
Delete the authorizer if it is no longer needed, and deploy the API if the stage does not use automatic deployment.
CLI:
aws
apigatewayv2 update-route --region <REGION> --api-id <API_ID>
--route-id <ROUTE_ID> --authorization-type NONE
aws
apigatewayv2 delete-authorizer --region <REGION> --api-id
<API_ID> --authorizer-id <AUTHORIZER_ID>
Note: rolling back allows anyone to invoke the API routes without authentication again.
Reference
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-access-control.html
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html
https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-authorizer.html