Featured image of post How to make an API request to an AWS microservice that is protected by IAM auth

How to make an API request to an AWS microservice that is protected by IAM auth

Intro

One of the authorization methods that AWS supports for the API Gateway endpoints is IAM authorization.

Two things are required to use IAM auth:

  • signed request using Signature Version 4
  • execute-api permission set up for the client for invoked endpoint

There are other authorization methods available like: Lambda authorizers or JWT authorizers you can read more about them here.

In today’s blog post, I will show you how to request a microservice that is protected by IAM auth.

The problem

For the blog post purpose, let’s imagine we have two microservices: Microservice A and Microservice B. Both of them were built using AWS lambda and API Gateway. We own Microservice A, and some other team owns Microservice B. We want to call Microservice B to get the response, it exposes the endpoint GET /items, and this endpoint is protected by IAM auth.

sequenceDiagram Microservice A->>+Microservice B: GET /items Microservice B ->>+ Microservice B: Authorize the request Microservice B ->>+ Microservice A: 200 Response

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import os
from urllib.parse import urlparse
from logging import Logger

import requests
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
from requests.exceptions import RequestException

class MicroserviceBClientClientError(Exception):
    pass


class MicroserviceBClient:
    def __init__(self, base_url: str, logger: Logger) -> None:
        self._base_url = base_url
        self._logger = logger

    @property
    def auth(self) -> BotoAWSRequestsAuth:
        return BotoAWSRequestsAuth(
            aws_host=urlparse(self._base_url).hostname, aws_region=os.environ["AWS_REGION"], aws_service="execute-api"
        )

    def get_items(self) -> None:
        try:
            self._logger.info("Getting items from MicroserviceB!")
            response = requests.post(
                f"{self._base_url}/items", auth=self.auth
            )
            response.raise_for_status()
            self._logger.info(f"Successful request! Response = {response.json()}")
        except RequestException as error:
            self._logger.error(f"An error occurred during request to `MicroserviceB` service! Error = {error}")
            raise MicroserviceBClientClientError

The aws-requests-auth does most of the things for us.

We need to provide the hostname of the service we want to call, the AWS region, and the service - in our case it is execute-api as we are working in a serverless lambda environment.

BotoAWSRequestsAuth generates the appropriate headers and adds them to the requests object. All we need to do is to add it as a auth param to the requests method.

Summary

It is as simple as that 😉 I hope you enjoyed it.

There are other methods that you can use to make such a request. The one I showed you is simple and easy. I have tested it on production, it is working 😉.

comments powered by Disqus
© All rights reserved
Built with Hugo
Theme Stack designed by Jimmy