Update 21/06/2020: following lots of feedback and questions on Twitter, I have updated the post to include a few more options.
Quite a few clients have asked me “Hey Yan, what API Gateway auth method should I use for this REST API?” so I thought I’d share my answer with everyone here.
This is the high-level decision tree I go through when deciding if and what auth method I should use. It’s directly applicable for over 90% of the use cases I have come across.
What about performing authentication and authorization inside the Lambda function itself?
The short answer is don’t do it!
When API Gateway rejects an unauthorized request, we don’t pay for the request. If we perform authentication and authorization inside our Lambda functions then we have to pay for both the API Gateway request and the Lambda invocation. This opens us up to naive denial-of-wallet attacks where attackers can generate lots of invalid requests against our API.
How do I use Auth0 or Okta for authentication?
With third-party systems such as Auth0 or Okta, we can integrate them with Cognito User Pools as SAML identity providers (IdPs). That way, we can still use COGNITO authorizer with API Gateway and Cognito User Pools would verify the identity of the caller with the SAML IdP.
How do I support social log-in such as Facebook or Google?
Similar to the above, we can also integrate Facebook, Google, Amazon or Apple with Cognito User Pools as social identity providers.
Where does Cognito Identity Pool fit in?
With Cognito Identity Pools, we can exchange federated identities from external identity providers with temporary IAM credentials.
Cognito Identity Pools is often used to provide access to client apps so they can access AWS services directly. For example, to allow IoT devices to publish and receive messages to & from AWS IoT Core.
The same approach can be applied with API Gateway. In which case, we need to use
AWS_IAM authentication and control access with IAM policies.
How can I use group-based authentication with Cognito User Pools?
This is possible with API Gateway, but it takes a lot of work as you can see from the official guide:
- add user groups
- assign an IAM role to each group to control which endpoints users in the group can access
- assign precedence to groups because a user can belong to multiple groups, and you need to resolve to one IAM role
- submit the ID token from Cognito when you send a request to API Gateway
- write a custom Lambda authorizer function (that’s right, you can’t use a Cognito authorizer!) to generate the correct policy based on the ID token
With AppSync, this is supported out-of-the-box and is one of the reasons why I prefer working with AppSync over API Gateway nowadays.
I have spent quite a bit of time with AppSync on a few projects, and it's really grown on me, big time. So much of what's difficult with API GW comes out-of-the-box.
— Yan Cui is making the AppSync Masterclass (@theburningmonk) June 1, 2020
What about API Gateway resource policy?
API Gateway resource policies offer another layer of control on top of the auth method on individual methods. We can whitelist/blacklist a range of IPs or AWS accounts, and we can also restrict access to the API to VPCs (see here for more details).
When we have internal tools that are only accessible through the company’s VPN, then we can use IP Whitelisting to restrict access to the VPN’s public IP addresses. However, this shouldn’t be the default. As much as possible, we should integrate the internal tool with a user management system such as Auth0 or Cognito and use the appropriate auth method.
IP Blacklisting is often used in conjunction with other authentication methods to explicitly deny a list of known, suspicious IPs. While this can be useful, it doesn’t scale well as it makes us responsible for maintaining the list of known, suspicious IPs. Also, where we have multiple REST APIs, we’d have to keep the resource policies in-sync to keep out the bad actors. A much better approach is to configure a Web ACL in AWS WAF and apply it to all our APIs.
We can use resource policy to make private APIs – that is, APIs that are only accessible through our VPCs. Much has been said about zero-trust networking, that is, no one should be trusted by default, even when they are already inside our network. So even when we use resource policy to enforce access through VPC, we should still employ one of the aforementioned auth methods in our REST APIs. Network security should be applied in addition to, not instead of, the layer 7 protections provided by API Gateway.
Finally, what about whitelisting AWS accounts? This is necessary when making cross-account API requests using
AWS_IAM auth. The REST API needs to white list the caller’s AWS account (or user/role) before the caller is able to use its IAM policy to provide access to our APIs. For more information about cross-account access management with IAM, have a read of these pages from the IAM documentation: