Accessing AWS HTTP API Gateway Endpoint With AWS Signature Version 4 Authentication Using Python

AWS API Gateway provides a scalable and secure way to expose your APIs to external clients. To ensure secure access to your API Gateway endpoints, AWS recommends using AWS Signature Version 4 authentication. In this article, we'll explore how to authenticate and interact with an AWS API Gateway endpoint using Python, leveraging the power of AWS Signature Version 4.

1. Overview of AWS Signature Version 4:

AWS Signature Version 4 is a signing process for AWS requests that helps ensure the integrity and authenticity of requests made to AWS services. It involves generating and including a signature in the request headers, which is then verified by AWS. This method prevents unauthorized access and tampering of data.

2. Setting up the AWS IAM Role in Account A:

To access the AWS API Gateway endpoint of AWS Account A, we'll assume an IAM role in the target AWS account (Account B). Follow these steps to set up the IAM role:

  1. Log in to the AWS Account B Management Console.
  2. Navigate to the IAM service.
  3. Create a new IAM role provide necessary permissions to access the API Gateway endpoint. You can use below policy in account B IAM role.
 1{
 2    "Version": "2012-10-17",
 3    "Statement": [
 4        {
 5            "Effect": "Allow",
 6            "Action": [
 7                "execute-api:Invoke"
 8            ],
 9            "Resource": "arn:aws:execute-api:*:*:*"
10        }
11    ]
12}
  1. Note down the ARN of the IAM role for later use.
  2. Now move to another account (Account A).
  3. Open IAM console and create a IAM role for lambda and below IAM policy.
 1
 2{
 3    "Version": "2012-10-17",
 4    "Statement": [
 5        {
 6            "Sid": "VisualEditor0",
 7            "Effect": "Allow",
 8            "Action": "sts:AssumeRole",
 9            "Resource": [
10                "<Account-B-IAM-Role-ARN>"
11            ]
12        }
13    ]
14}

Note: Change "" with Account B IAM Role ARN.

  1. Now, Create a Lambda function to assume Account B IAM role and Access the API Gateway.

3. Create a Lambda Function using AWS Signature Version 4 in Python:

To authenticate the requests using AWS Signature Version 4 in Python, we'll need to install the boto3 library and use the requests library. Follow these steps:

  1. Install the required Python packages: pip install boto3 requests.
  2. Import the necessary modules in your Python script:
1import requests
2import datetime
3import hmac
4import hashlib
5import boto3
  1. Assume the IAM role using the boto3 library:
1role_arn = '<IAM_ROLE_ARN>'
2sts_client = boto3.client('sts')
3response = sts_client.assume_role(
4    RoleArn=role_arn,
5    RoleSessionName='AssumedRoleSession'
6)
7access_key = response['Credentials']['AccessKeyId']
8secret_key = response['Credentials']['SecretAccessKey']
9session_token = response['Credentials']['SessionToken']
  1. Generate the necessary headers for the AWS API Gateway request:
1api_gateway_url = '<API_GATEWAY_URL>'
2now = datetime.datetime.utcnow()
3amz_date = now.strftime('%Y%m%dT%H%M%SZ')
4headers = {
5    'Host': '<API_GATEWAY_HOST>',
6    'X-Amz-Date': amz_date,
7    'X-Amz-Security-Token': session_token
8}
  1. Generate the canonical request, string to sign, signing key, and signature using the AWS Signature Version 4 algorithm. You can use the following code as a starting point:
1canonical_request = ...
2string_to_sign = ...
3date_key = ...
4region_key = ...
5service_key = ...
6signing_key = ...
7signature = ...
  1. Add the Authorization header to the request headers:
1auth_header = f"AWS4-HMAC-SHA256 Credential={access_key}/{credential_scope}, SignedHeaders=host;x
2
3-amz-date;x-amz-security-token, Signature={signature}"
4headers['Authorization'] = auth_header
  1. Sending Requests to the AWS API Gateway Endpoint: To send a request to the AWS API Gateway endpoint, use the requests library:
1response = requests.get(api_gateway_url, headers=headers)
  1. Complete Python Code Example: Here's a complete example of Python code to access an AWS API Gateway endpoint using AWS Signature Version 4 authentication:
 1
 2import requests
 3import datetime
 4import hmac
 5import hashlib
 6import boto3
 7
 8def lambda_handler(event, context):
 9    
10    # Assign Variables 
11    ## Cross Account IAM role
12    role_arn = 'arn:aws:iam::<account-number>:role/<Cross-Account-IAM-Role-For-API-Gateway>'
13    ## API gateway endpoint
14    host_url = '1xesdf32de.execute-api.ap-south-1.amazonaws.com'
15    ## API gateway URI
16    host_uri = '/hello'
17    
18    # Create an STS client
19    sts_client = boto3.client('sts')
20
21    # Assume the IAM role to retrieve temporary credentials
22    response = sts_client.assume_role(
23        RoleArn=role_arn,
24        RoleSessionName='AssumedRoleSession'
25    )
26
27    # Extract the temporary credentials
28    access_key = response['Credentials']['AccessKeyId']
29    secret_key = response['Credentials']['SecretAccessKey']
30    session_token = response['Credentials']['SessionToken']
31
32    # API Gateway endpoint URL
33    api_gateway_url = "https://"+host_url+host_uri
34
35    # Generate the current timestamp
36    now = datetime.datetime.utcnow()
37    amz_date = now.strftime('%Y%m%dT%H%M%SZ')
38
39    # Generate the request headers
40    headers = {
41        'Host': host_url,
42        'X-Amz-Date': amz_date,
43        'X-Amz-Security-Token': session_token
44    }
45
46    # Generate the canonical request
47    canonical_request = f"GET\n/hello\n\nhost:{headers['Host']}\nx-amz-date:{amz_date}\nx-amz-security-token:{session_token}\n\nhost;x-amz-date;x-amz-security-token\n{hashlib.sha256(b'').hexdigest()}"
48
49    # Generate the string to sign
50    credential_scope = f"{now.strftime('%Y%m%d')}/ap-south-1/execute-api/aws4_request"
51    string_to_sign = f"AWS4-HMAC-SHA256\n{amz_date}\n{credential_scope}\n{hashlib.sha256(canonical_request.encode()).hexdigest()}"
52
53    # Generate the signing key
54    date_key = hmac.new(('AWS4' + secret_key).encode(), now.strftime('%Y%m%d').encode(), hashlib.sha256).digest()
55    region_key = hmac.new(date_key, 'ap-south-1'.encode(), hashlib.sha256).digest()
56    service_key = hmac.new(region_key, 'execute-api'.encode(), hashlib.sha256).digest()
57    signing_key = hmac.new(service_key, 'aws4_request'.encode(), hashlib.sha256).digest()
58
59    # Generate the signature
60    signature = hmac.new(signing_key, string_to_sign.encode(), hashlib.sha256).hexdigest()
61
62    # Generate the authorization header
63    auth_header = f"AWS4-HMAC-SHA256 Credential={access_key}/{credential_scope}, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature={signature}"
64    headers['Authorization'] = auth_header
65
66    # Send the signed request
67    response = requests.get(api_gateway_url, headers=headers)
68
69    # Print the response from the API Gateway endpoint
70    print(response.text)

4. Test your lambda:

Now you can test your lambda. Lambda will assume your AWS Account B IAM role, Get the temp credential and Access the API gateway Endpoint.

5. Conclusion:

In this article, we explored how to access an AWS API Gateway endpoint using AWS Signature Version 4 authentication. We learned how to assume an IAM role, generate the required headers, and send authenticated requests to the API Gateway endpoint using Python. By leveraging AWS Signature Version 4, you can ensure secure and authorized access to your API Gateway resources.

Remember to follow AWS security best practices and configure appropriate IAM roles and permissions to control access to your resources.

By implementing AWS Signature Version 4 authentication in your Python applications, you can interact securely with AWS API Gateway endpoints and build robust and scalable solutions.

Now you're ready to securely authenticate and interact with AWS API Gateway using AWS Signature Version 4 in Python!

AWS API Gateway

We hope you found this article helpful. Stay tuned for more AWS-related tutorials and guides!

I ❤ AWS! Happy Cloud Computing! 🧑‍💻 Enjoy #Cloudkaramchari