Serverless 4: Authorizers and IAM Policy
Already checked the other three tutorials before this one? If not, check part 1, part 2 and part 3 to understand where we are now and follow this last part. If yes, let’s go ahead, because this last step will treat an extremely important part regarding application development architecture: security.
There are many way to authorize an API consumer, and AWS itself has wonderful documentation about this here. For this article, I will use the Lambda authorizer with a Python function receiveing a parameter in the request header and evaluating the access permission or denial.
The architecture solution , taken from this link, is exactly like this:
The client request an API Gateway endpoint passing in its header a key/value parameter with a token and the Lambda function returns not a YES/NO answer but a JSON structure identical to an IAM Policy, containing:
· Principal ID: unique identifier of request caller.
· Action: the action the resource wants to do (in this case, invoke an API)
· Effect: the effect applied to the action, either Allow or Deny
· Resource: AWS resource unique identifier (ARN) that will receive the action
Inside the Lambda function, it is possible to define the authorization key that will be passed in the header, which I decided to name authorizationToken. So without further ado, let’s create the function and associate it with the API Gateway from before.
Lambda Authorizer
Go to the Lambda dashboard and choose Create Function.
Then, select Author from Scratch and fill in the information:
· Function Name: API_Authorizer
· Runtime: Python 3.8
Do not change anything under Permissions, that way the console itself will create a predefined role to run this function with proper access. At the end, click Create Function.
In the code edit area, in case you cannot see any Python code, click twice in lambda_function.py in the left side and replace the default code with the following:
import jsondef lambda_handler(event, context):
token = event['authorizationToken']
if(token == "allow"):
return generatePolicy('apiCaller','Allow', event['methodArn'])
else:
return generatePolicy('apiCaller','Deny', event['methodArn'])
def generatePolicy(principalId, effect, methodArn):
authResponse = {}
authResponse['principalId'] = principalId
if effect and methodArn:
policyDocument = {
'Version': '2012–10–17',
'Statement': [
{
'Action': 'execute-api:Invoke',
'Effect': effect,
'Resource': methodArn
}
]
}
authResponse['policyDocument'] = policyDocument
return authResponse
Watch out the code structure when pasting, because Python uses indentation and hierarchy in line position. Check out the image below for the correct structure.
To finish, click Deploy.
API Gateway
Configure the authorizer inside API Gateway is quite simple and demands just a few configurations:
Go to the API Gateway dashboard and in the left side, click Authorizers.
Next, click the button Create New Authorizer and fill in the information:
· Name: API_Auth
· Type: Lambda
· Lambda Function: API_Authorizer
· Lambda Event Payload: Token
· Token Source: authorizationToken
· Authorization Caching: unchecked
Click Create and AWS will ask for permissions for the API Gateway to call the Lambda function, and you must Grant & Create. Next, note the authorizer will show a little Test button. Click it!
There, it is possible to validate the Lambda function return code by typing allow (which should return a positive policy), or deny/any text (which should return a negative policy).
Now, you must associate the authorizer with the desired resources and publish your API to test on external environments. Click close and in the left menu, choose Resources.
On your endpoints list, select the GET method (the list users API built in Part 2) and click Method Request.
In the next screen, under Settings, section Authorization, click the little pencil icon, select the authorizer created previously and hit the little check box.
Finally, in the upper dropdown Actions, choose Deploy API. Select the environment created in Part 1 (I named mine prod) and click Deploy.
You will be automatically redirected to the Stages section, so take the moment to copy the GET Invoke URL.
Testing your API
There are a couple of software available to test APIs, such as Katalon Studio, SoapUI or Postman, which I chose to use in the next steps.
So, download, install and execute Postman, click the icon [+] to add a new request.
Double-check if the request verb is GET and paste the Invoke URL in the address area. Next, click Send.
If everything went well, you should get a 401 Unauthorized response. So, click where it says Headers, add the following key/value and click Send.
· authorizationToken: allow
This time, you should get an API response with status 200 OK, meaning that your request was succesfully authorized.
Conclusion
This authorization type used here is simple but adds a new layer of security to the API calls, trying to prevent some kind of denial of service attack or unknown requests trying to corrupt your database.
In this case, the authorization passkey was just a word (allow/deny), but it can be a series of letters/numbers/special characters, an MD5 hashed password or tokens changing according to time or some other criteira, validated against a controller table, etc. There are many possibilities to lock your application and, as every technology, constantly evolving.
At last, the goal of these articles was to share with you the knowledge obtained in the past few months e understand how AWS tools are powerful when we talk about saving money and reduce processing time to deliver results.
And this is only the beginning. See you in next article and keep learning!