Invoke an AWS Lambda function from IAM. It can be used in combination with other request plugins to secure, manage or extend the function.
Terminology
plugin
: a plugin executing actions inside IAM before or after a request has been proxied to the upstream API.Service
: the IAM entity representing an external upstream API or microservice.Route
: the IAM entity representing a way to map downstream requests to upstream services.Consumer
: the IAM entity representing a developer or machine using the API. When using IAM, a Consumer only communicates with IAM which proxies every call to the said upstream API.Credential
: a unique string associated with a Consumer, also referred to as an API key.upstream service
: this refers to your own API/service sitting behind IAM, to which client requests are forwarded.
Configuration
This plugin is compatible with requests with the following protocols:
http
https
This plugin is compatible with DB-less mode.
Enabling the plugin on a Service
With a database
Configure this plugin on a Service by making the following request:
$ curl -X POST http://localhost:8001/services/{service}/plugins \
--data "name=aws-lambda" \
--data-urlencode "config.aws_key=AWS_KEY" \
--data-urlencode "config.aws_secret=AWS_SECRET" \
--data "config.aws_region=AWS_REGION" \
--data "config.function_name=LAMBDA_FUNCTION_NAME"
Without a database
Configure this plugin on a Service by adding this section do your declarative configuration file:
plugins:
- name: aws-lambda
service: {service}
config:
aws_key: AWS_KEY
aws_secret: AWS_SECRET
aws_region: AWS_REGION
function_name: LAMBDA_FUNCTION_NAME
In both cases, {service}
is the id
or name
of the Service that this plugin configuration will target.
Enabling the plugin on a Route
With a database
Configure this plugin on a Route with:
$ curl -X POST http://localhost:8001/routes/{route}/plugins \
--data "name=aws-lambda" \
--data-urlencode "config.aws_key=AWS_KEY" \
--data-urlencode "config.aws_secret=AWS_SECRET" \
--data "config.aws_region=AWS_REGION" \
--data "config.function_name=LAMBDA_FUNCTION_NAME"
Without a database
Configure this plugin on a Route by adding this section do your declarative configuration file:
plugins:
- name: aws-lambda
route: {route}
config:
aws_key: AWS_KEY
aws_secret: AWS_SECRET
aws_region: AWS_REGION
function_name: LAMBDA_FUNCTION_NAME
In both cases, {route}
is the id
or name
of the Route that this plugin configuration will target.
Enabling the plugin on a Consumer
With a database
You can use the http://localhost:8001/plugins
endpoint to enable this plugin
on specific Consumers:
$ curl -X POST http://localhost:8001/consumers/{consumer}/plugins \
--data "name=aws-lambda" \
\
--data-urlencode "config.aws_key=AWS_KEY" \
--data-urlencode "config.aws_secret=AWS_SECRET" \
--data "config.aws_region=AWS_REGION" \
--data "config.function_name=LAMBDA_FUNCTION_NAME"
Without a database
Configure this plugin on a Consumer by adding this section do your declarative configuration file:
plugins:
- name: aws-lambda
consumer: {consumer}
config:
aws_key: AWS_KEY
aws_secret: AWS_SECRET
aws_region: AWS_REGION
function_name: LAMBDA_FUNCTION_NAME
In both cases, {consumer}
is the id
or username
of the Consumer that this plugin configuration will target.
You can combine consumer_id
and
service_id
in the same request, to furthermore narrow the scope of the plugin.
Global plugins
- Using a database, all plugins can be configured using the
http://localhost:8001/plugins/
endpoint. - Without a database, all plugins can be configured via the
plugins:
entry on the declarative configuration file.
A plugin which is not associated to any Service, Route or Consumer (or API, if you are using an older version of IAM) is considered "global", and will be run on every request. Read the Plugin Reference and the Plugin Precedence sections for more information.
Parameters
Here's a list of all the parameters which can be used in this plugin's configuration:
form parameter | description |
---|---|
name | The name of the plugin to use, in this case aws-lambda |
service_id | The id of the Service which this plugin will target. |
route_id | The id of the Route which this plugin will target. |
enabled default value: true | Whether this plugin will be applied. |
consumer_id | The id of the Consumer which this plugin will target. |
config.aws_key
|
The AWS key credential to be used when invoking the function |
config.aws_secret
|
The AWS secret credential to be used when invoking the function |
config.aws_region
|
The AWS region where the Lambda function is located. Regions supported are: |
config.function_name
|
The AWS Lambda function name to invoke |
config.qualifier
optional |
The |
config.invocation_type
optional default value:
|
The |
config.log_type
optional default value:
|
The |
config.timeout
optional default value:
|
An optional timeout in milliseconds when invoking the function |
config.keepalive
optional default value:
|
An optional value in milliseconds that defines how long an idle connection will live before being closed |
config.unhandled_status
optional default value:
|
The response status code to use (instead of the default |
config.forward_request_body
optional default value:
|
An optional value that defines whether the request body is to be sent in the |
config.forward_request_headers
optional default value:
|
An optional value that defines whether the original HTTP request headers are to be sent as a map in the |
config.forward_request_method
optional default value:
|
An optional value that defines whether the original HTTP request method verb is to be sent in the |
config.forward_request_uri
optional default value:
|
An optional value that defines whether the original HTTP request URI is to be sent in the |
config.is_proxy_integration
optional default value:
|
An optional value that defines whether the response format to receive from the Lambda to this format. Note that the parameter |
Reminder: curl by default sends payloads with an
application/x-www-form-urlencoded
MIME type, which will naturally be URL-
decoded by IAM. To ensure special characters that are likely to appear in your
AWS key or secret (like +
) are correctly decoded, you must URL-encode them,
hence use --data-urlencode
if you are using curl. Alternatives to this
approach would be to send your payload with a different MIME type (like
application/json
), or to use a different HTTP client.
Sending parameters
Any form parameter sent along with the request, will be also sent as an argument to the AWS Lambda function.
Known Issues
Use a fake upstream service
When using the AWS Lambda plugin, the response will be returned by the plugin
itself without proxying the request to any upstream service. This means that
a Service's host
, port
, path
properties will be ignored, but must still
be specified for the entity to be validated by IAM. The host
property in
particular must either be an IP address, or a hostname that gets resolved by
your nameserver.
Response plugins
There is a known limitation in the system that prevents some response plugins from being executed. We are planning to remove this limitation in the future.
Step By Step Guide
The Steps
- Access to AWS Console as user allowed to operate with lambda functions and create user and roles.
- Create an Execution role in AWS
- Create an user which will be invoke the function via IAM, test it.
- Create a Service & Route in IAM, add the aws-lambda plugin linked to our aws function and execute it.
Configure
-
First, let's create an execution role called
LambdaExecutor
for our lambda function.In IAM Console create a new Role choosing the AWS Lambda service, there will be no policies as our function in this example will simply execute itself giving us back an hardcoded JSON as response without accessing other AWS resources.
-
Now let's create a user named IAMInvoker, used by our IAM API gateway to invoke the function.
In IAM Console create a new user, must be provided to it programmatic access via Access and Secret keys; then will attach existing policies directly particularly the AWSLambdaRole predefined. Once the user creation is confirmed, store Access Key and Secret Key in a safe place.
-
Now we need to create the lambda function itself, will do so in N.Virginia Region (code us-east-1).
In Lambda Management, create a new function Mylambda, there will be no blueprint as we are going to paste the code below; for the execution role let's choose an existing role specifically LambdaExecutor created previously
Use the inline code below to have a simple JSON response in return, note this is code for Python 3.6 interpreter.
import json def lambda_handler(event, context): """ If is_proxy_integration is set to true : jsonbody='''{"statusCode": 200, "body": {"response": "yes"}}''' """ jsonbody='''{"response": "yes"}''' return json.loads(jsonbody)
Test the lambda function from the AWS console and make sure the execution succeeds.
-
Finally we setup a Service & Route in IAM and link it to the function just created.
With a database
curl -i -X POST http://{kong_hostname}:8001/services \
--data 'name=lambda1' \
--data 'url=http://localhost:8000' \
The Service doesn't really need a real url
since we are not going to have an HTTP call to upstream but rather a response generated by our function.
Also create a Route for the Service:
curl -i -X POST http://{kong_hostname}:8001/services/lambda1/routes \
--data 'paths[1]=/lambda1'
Add the plugin:
curl -i -X POST http://{kong_hostname}:8001/services/lambda1/plugins \
--data 'name=aws-lambda' \
--data-urlencode 'config.aws_key={IAMInvoker user key}' \
--data-urlencode 'config.aws_secret={IAMInvoker user secret}' \
--data 'config.aws_region=us-east-1' \
--data 'config.function_name=MyLambda'
Without a database
Add a Service, Route and Plugin to the declarative config file:
services:
- name: lambda1
url: http://localhost:8000
routes:
- service: lambda1
paths: [ "/lambda1" ]
plugins:
- service: lambda1
name: aws-lambda
config:
aws_key: {IAMInvoker user key}
aws_secret: {IAMInvoker user secret}
aws_region: us-east-1
function_name: MyLambda
Once everything is created, call the Service and verify the correct invocation, execution and response:
curl http://{kong_hostname}:8000/lambda1
Additional headers:
x-amzn-Remapped-Content-Length, X-Amzn-Trace-Id, x-amzn-RequestId
JSON response:
{"response": "yes"}
Have fun leveraging the power of AWS Lambda in IAM!