Authentication and Authorization in AWS API Gateway
1. Overview
The aim of this workshop is, on one hand, show you how you can integrate the authentication in an API Gateway. On the other hand, we will explore different authorization mechanisms used by the API Gateway.
What you will learn
In this workshop you will learn:
- What is an AWS API Gateway
- What are the security settings for API Gateway
- How to create a Cognito User Pool as an authentication method
- How to integrate Cognito with API Gateway to provide it with an authentication method
- How to define and set up a custom authorizer
- How to protect your API Gateway in different ways
Overall, you will learn how to create a secure and customizable API Gateway. Additionally, you will have experimented with multiple security options that API Gateway provide us and which are usually useful in many projects.
2. What is an API Gateway
According to the AWS Documentation:
Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. APIs act as the “front door” for applications to access data, business logic, or functionality from your backend services. Using API Gateway, you can create RESTful APIs and WebSocket APIs that enable real-time two-way communication applications. API Gateway supports containerized and serverless workloads, as well as web applications.
Features:
- Restful and Websockets
- Private integration with AWS Elastic Load Balancers (ALB and ELB)
- Private integration with Amazon CloudMap
- Resiliency: throttling, cache and TTL (REST)
- Easy to create and deploy
- Monitoring: Integration with Amazon CloudWatch
- Authorization: leverage signature version 4 by signing requests via IAM and create custom token validations
- API keys: set fine-grained access permissions on each API key
- SDK generation: you can generate client SDKs for a number of platforms which you can use to quickly test new APIs from your applications and distribute SDKs to third-party developers
- Lifecycle management: you can run multiple versions of the same API simultaneously so that applications can continue to call previous API versions even after the latest versions are published
- Security: It easily integrates with AWS WAF
- DNS: You can easily define a custom domain name and a SSL certificate for the API Gateway
3. Amazon Cognito
According to the AWS Documentation:
Amazon Cognito lets you add user sign-up, sign-in, and access control to your web and mobile apps quickly and easily. Amazon Cognito scales to millions of users and supports sign-in with social identity providers, such as Facebook, Google, and Amazon, and enterprise identity providers via SAML 2.0.
Features
-
Access control to AWS resources: You can define roles and map users to different roles so your app can access only the resources that are authorized for each user
-
Standards-based authentication: It uses uses identity management standards including OpenID Connect, OAuth 2.0, and SAML 2.0
-
Adaptive authentication: when Amazon Cognito detects unusual sign-in activity, such as sign-in attempts from new locations and devices, it assigns a risk score to the activity and lets you choose to either prompt users for additional verification or block the sign-in request
-
Protection from compromised credentials: When Amazon Cognito detects users have entered credentials that have been compromised elsewhere, it prompts them to change their password
-
Supports Multiple Compliance Programs: It is HIPAA eligible and PCI DSS, SOC, and ISO/IEC 27001, ISO/IEC 27017, ISO/IEC 27018, and ISO 9001 compliant.
Components
(for more details about these components, visit the AWS Documentation)
- User Pool:
- Design sign-up and sign-in webpages for your app.
- Access and manage user data.
- Track user device, location, and IP address, and adapt to sign-in requests of different risk levels.
- Use a custom authentication flow for your app.
- Federated Identity:
- Give your users access to AWS resources, such as an Amazon Simple Storage Service (Amazon S3) bucket or an Amazon DynamoDB table.
- Generate temporary AWS credentials for unauthenticated users.
4. Part 0: Set up
First of all, we need to set up the environment to continue with this lab. We need to first clone the repository https://github.com/ronaldtf/aws-auth-apigateway
$> git clone https://github.com/ronaldtf/aws-auth-apigateway.git
The directory structure is as follows:
- deployment: It contains the infrastructure as a code to set up the initial infrastructure. Additonal, it contains a script to run the infrastructure from the console without needing to launch it from CloudFormation
- resources: It contains the files needed for running the workshop
- web: It contains the web page needed to perform different tests. As I will show you later, the lab goes a bit beyond and we will run some curl commands at the end of the lab (I have opted to do it this way for simplicity)
In order to set up the infrastructure, we can opt for one of these methods:
- Run the deployment script
- Launch the code from the AWS Console
Case 1: Run the deployment script
Requirements
Before running the script, we need to verify that we have our environment ready to launch it. You should check that you have installed and configured the following tools:
AWS Command Line Interface:: AWS CLI is a tool that let us send requests to AWS API to perform certain actions. Regarding the operating system you use, you can either download the installer and install it or use the pip
installer. To get details instructions of how to do this follow the AWS Command Line Interface page. For instance, for Unix OS, you need Python3 and pip to be installed. Then, execute:
$ pip install awscli
- aws-mfa: (Mandatory, if using MFA) This is a script that help us to manage AWS security credentials using MFA. Please, follow the instructions from the pip page. For instance, for Unix OS, you need Python3 and pip to be installed. Then execute:
$ pip install aws-mfa
We need to set up our environment to later be able to deploy our resources. To do so, we must follow the AWS documentation. We describe below the procedure anyway.
In the IAM Section in the AWS Console, we have to go to users and select the user we want to use for the deployment. We select Security credentials
and Create access key
(if not previously created). Copy the user access key
and secret access key
provided.
If you do not find the file
~/.aws/credentials
in the cases below, type:
$ aws configure
and set the default region (e.g. eu-west-1).
Case 1: Unique account for users and services
If you are not using MFA and simply use an account for users and services (which is not recommended), just set the values copied above in an ~/.aws/credentials
file:
[default]
aws_access_key_id = YOURACCESSKEYID
aws_secret_access_key = YOURSECRETACCESSKEY
Case 2: AWS Users Account and AWS Services Account separately
If you use MFA and a user account for the IAM users and a service account for the services (and where you want to deploy your services) as shown in the image below…
… you must follow this configuration:
- Install the aws-mfa tool
$ pip install aws-mfa
- Define a profile (e.g. lab-long-term) and update your ~/.aws/config file by including the profile options.
[profile default]
...
[profile lab-long-term]
region = eu-west-1
output = json
role_arn = arn:aws:iam::123456789012:role/role_to_be_assumed
source_profile = default
NOTE: the
source_profile
is the profile that gives us permissions to do an assume role. Therefore, we need to define those credentials for it in the~/.aws/config
file.
- Update your credentials file, by creating a tag profile by appending ‘long-term’ to the profile name (replace the values below with the appropriate ones for your case):
[lab-long-term]
aws_access_key_id = YOURACCESSKEYID
aws_secret_access_key = YOURSECRETACCESSKEY
aws_mfa_device = arn:aws:iam::123456789012:mfa/iam_user
- Run the aws-mfa command to set the credentials with the profile
aws-mfa --profile lab
This will place the right credentials in the ~/.aws/credentials
file. However, note that this credentials will expire and we will need to execute the command below again once they are expired.
Set up
Before running the script, we need to edit it and set the following parameters:
- PROFILE: The profile name associated to your credentials
- STACK_NAME: A name for the CloudFormation stack to be deployed
The, we simply run the script:
$> ./deploy.sh
Case 2: Deploy it from the console
-
Create a bucket and place the
python.zip
file in that bucket -
Go to the CloudFormation service, and deploy a stack by selecting the
deploy.yaml
file placed in thedeployment
directory. Pass the name of the created bucket as a parameter -
Once done, you have to get the output of the Stack and fill in the values of the variables in
web/js/config.js
-
Upload the
test.json
file to the S3 bucket indicated in the output (key:ReferredBucket
.
Post set-up
In order to do the test, you need to create a user in Cognito
NOTE: User name must be an email address!
5. Part 1: Cognito authentication
In order to test this example, we will use 2 methods:
- Using the example page
- Using the curl command (by adding the
Authorization
header to your request)
The procedure of how to perform this will be explained during the workshop
6. Part 2: Signed requests
In this case, we will test the example by using the example page (doing it with the curl command is possible, but complex).
Following the Part 1, will you be able to configure this case?
7. Part 3: API Key protection
API keys are alphanumeric string values that you distribute to application developer customers to grant access to your API. You can use API keys together with usage plans or Lambda authorizers to control access to your APIs. API Gateway can generate API keys on your behalf, or you can import them from a CSV file.
In order to test this example, we will use 2 methods:
- Using the example page (NOTE: you need to adjust some settings)
- Using the curl command (by adding the
X-API-Key
header to your request)
To implement this, you need:
- An API Key: you can either create the usage plan or import an existing one.
- An usage plan: a usage plan is linked to the API Gateway stage. You can define the the bursting, throttling and usage plans.
To test this, use a new API Gateway resource and method. You can reuse the default public lambda as the backend for this case.
NOTE: Bear in mind that, after you have changed the created method by using the API key, you need to redeploy your API Gateway
8. Part 4: Use custom Tokens
For generating a custom token, visit JWT IO page
Do you know how to customize your current authorizer to validate your custom token (instead of the one provided by Cognito)?
NOTE: There is already a lambda implemented to validate the custom token (named
<stack_name>-authorizer
). This authorizer only acceptsHS256
encoded tokens (bear that in mind, otherwise it would not work)
IMPORTANT: If you are going to use Cognito tokens, you must:
- Change the token type to HS256 (the implemented custom authorizer only support this encryption type)
- Remove the aud field (otherwise, we will get an error
Invalid audience
)
For this case, we will only use the
curl
command to test it. Remember to useAuthorization
header to add the token in the authorizer (otherwise, it will not work)
9. Part 5: Define Policies
Extracted from AWS Documentation
API Gateway resource policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:region:account-id:api-id/",
"Condition": {
"IpAddress": {
"aws:SourceIp": ["192.0.2.0/24", "198.51.100.0/24" ]
}
}
}
]
}
API Gateway resource policy with IAM
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "",
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:region:account-id:api-id/"
],
"Condition" : {
"StringEquals": {
"aws:SourceVpc": "vpc-2f09a348"
}
}
}
]
}
API Gateway resource policy with Cognito
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:region:account-id:api-id/",
"Condition": {
"IpAddress": {
"aws:SourceIp": ["192.0.2.0/24", "198.51.100.0/24" ]
}
}
}
]
}
API Gateway resource policy with lambda authorizer
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:region:account-id:api-id/"
],
"Condition" : {
"StringNotEquals": {
"aws:SourceVpce": "vpce-1a2b3c4d"
}
}
}
]
}
10. Part 6 (BONUS): Create Private APIs
This lab goes beyond the purpose of the workshop. However, I have found interesting to include a section here.
This is the procedure:
-
Create a private API Gateway and a mock resource
-
Create an interface endpoint (execute-api) to the API Gateway to be used within a VPC
-
To grant access to your VPC endpoint, create a resource policy and attach it to your API
-
From an EC2 instance from your VPC, call a method by using
curl
and the interface endpoint as an endpoint
11. Congratulations!
Now that you know…
- How to protect your API Gateway resources by using different options:
- Requests signed with IAM credentials
- Cognito authorizers
- API Keys
- How to configure your API Gateway by using custom JWT tokens
- How to add additional security to the API Gateway by defining policies
- (BONUS: create a private API Gateway)
… it’s time to put your hands on new projects and start new challenges!