Skip to content

Plugin that enables the secure use of AWS Lambdas as upstreams in Kong using Lambda URLs

License

Notifications You must be signed in to change notification settings

LEGO/kong-aws-request-signing

Repository files navigation

KONG-AWS-REQUEST-SIGNING

Build

About

This plugin will sign a request with AWS SIGV4 and temporary credentials from sts.amazonaws.com requested using an OAuth token.

The AWS SIGV4 signature enables secure proxying directly towards AWS services such as Lambda URLs.

At the same time it drives down cost and complexity by excluding the AWS API Gateway and allowing to use AWS Lambdas directly.

The required AWS setup to make the plugin work with your Lambda HTTPS endpoint is described below.

Note that this plugin cannot be used in combination with Kong upstreams.

Plugin configuration parameters

aws_assume_role_arn -- ARN of the IAM role that the plugin will try to assume
type = "string"
required = true

aws_assume_role_name -- Name of the role above.
type = "string"
required = true

aws_region -- AWS region where your Lambda is deployed to
type = "string"
required = true

aws_service -- AWS Service you are trying to access (lambda and s3 were tested)
type = "string"
required = true

override_target_host -- To be used when deploying multiple lambdas on a single Kong service (because lambdas have different URLs)
type = "string"
required = false

override_target_port -- To be used when deploying a Lambda on a Kong service that listens on a port other than `443`
type = "number"
required = false

override_target_protocol -- To be used when deploying a Lambda on a Kong service that has a protocol different than `https`
type = "string"
one_of = "http", "https"
required = false

return_aws_sts_error -- Whether to return the AWS STS response status and body when credentials fetching failed.
type = "boolean"
default = false
required = false

sign_query -- Controls if the signature will be sent in the header or in the query. By default, header is used, if enabled will sign the query.
type = "boolean"
required = true
default = false

preserve_auth_header -- Controls if the bearer token will be passed to the upstream
type = "boolean"
required = true
default = true

preserve_auth_header_key -- The header key where the bearer token will be saved and passed to the upstream. works only if 'preserve_auth_header' parameter above is set to true.
type = "string"
required = true
default = "x-authorization"

use_altered_target -- if another plugin changes the target to something other than what is registered on the service - use that target rather than the overrides of this plugin.
type = "boolean"
required = true
default = false

Using multiple Lambdas with the same Kong Service

The plugin can be enabled on a per-service and per-route basis. When enabled for a route, the plugin will direct traffic to the service's upstream Lambda target, unless override_target_host is specified.

If multiple Lambdas are needed for a single service, each route must have the plugin enabled with override_target_host configured, so that requests are correctly routed to the right Lambda.

If override_target_host is not specified and multiple Lambdas are used in the service, all routes will be served by the same service-level host.

You can also set the service protocol and host to something like http://example.com and then use override_target_protocol and override_target_host to changed it on the path level.

The use_altered_target is useful if another plugin with higher priority has changed the target, and we would like that to take precedence over the overrides of this plugin. This can be used when combining this plugin with e.g. the canary-release.

Installing the plugin

There are two things necessary to make a custom plugin work in Kong:

  1. Load the plugin files.

The easiest way to install the plugin is using luarocks.

luarocks install https://github.com/LEGO/kong-aws-request-signing/raw/main/rocks/kong-aws-request-signing-1.0.5-3.all.rock

You can substitute 1.0.0-3 in the command above with any other version you want to install.

If running Kong using the Helm chart, you will need to create a config map with the plugin files and mount it to /opt/kong/plugins/aws-request-signing. You can read more about this on Kong's website.

  1. Specify that you want to use the plugin by modifying the plugins property in the Kong configuration.

Add the custom plugin’s name to the list of plugins in your Kong configuration:

plugins = bundled, aws-request-signing

If you are using the Kong helm chart, create a configMap with the plugin files and add it to your values.yaml file:

# values.yaml
plugins:
  configMaps:
  - name: kong-plugin-aws-request-signing
    pluginName: aws-request-signing

Signing requests containing a body

In case of requests containing a body, the plugin is highly reliant on the nginx configuration, because it needs to access the body to sign it. The behavior is controlled by the following Kong configuration parameters:

nginx_http_client_max_body_size
nginx_http_client_body_buffer_size

Kong docs reference.

The default value for max body size is 0, which means unlimited, so consider setting the nginx_http_client_body_buffer_size as high as you consider reasonable, as requests containing a bigger body, will fail.

AWS Setup required

  1. You have a Lambda function deployed with Function URL enabled and Auth type : AWS_IAM or you have an S3 bucket with public access disabled.
Show image

Lambda example

  1. Your OpenID Connect provider is added to AWS IAM
  2. You have a role with arn:aws:iam::aws:policy/AWSLambda_FullAccess and/or arn:aws:iam::aws:policy/AmazonS3FullAccess permission (or any other permission that grants access to your desired AWS service ) and the trust relationship below:
Show JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "${arn_of_the_open_id_connect_provider_step_1}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "${the_open_id_connect_provider_step_1}:aud": "${audience_of_the_lambda_given_by_your_open_id_provider}"
                }
            }
        }
    ]
}

So if your provider is https://sts.windows.net/organization.onmicrosoft.com/ and your app identity is app_identity_1, the trust relationship above will look like:

Show JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::300000000000:oidc-provider/sts.windows.net/organization.onmicrosoft.com/"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "sts.windows.net/organization.onmicrosoft.com/:aud": "app_identity_1"
                }
            }
        }
    ]
}

About the code and differences from Kong Lambda Plugin

Some of the code was reused from Kong Lambda Plugin specifically the SIGV4 creation code and some parts for getting the temporary credentials from AWS STS. There are some considerable differences that will be outlined below:

  1. Unlike Kong-Lambda This plugin does not perform the Lambda invocation. But only signs the request coming from the consumer which Kong then forwards to the upstream that it is configured in the service that the plugin is bound to.
  2. The plugin works only with temporary credentials that are fetched from sts.amazonaws.com using AssumeRoleWithWebIdentity, this requires some configuration in AWS which can be found above.
  3. This plugin has a low priority and is compatible with the rest of Kong plugins because as mentioned above, it only performs SIGV4 on the request and then appends the necessary headers to be authorized in AWS.

Open Source Attribution

License

Modified Apache 2.0 (Section 6)