Skip to content

Commit

Permalink
feat: added parameter to respect altered target (#42)
Browse files Browse the repository at this point in the history
* making the plugin use the context target if instructed

* version bump

* Update schema.lua

* mentioning new configs in readme

* Update Readme.md

Co-authored-by: alexpopaconst <[email protected]>

* Update kong/plugins/aws-request-signing/schema.lua

Co-authored-by: alexpopaconst <[email protected]>

---------

Co-authored-by: Henrik Hafstrøm Johnsen <[email protected]>
Co-authored-by: alexpopaconst <[email protected]>
  • Loading branch information
3 people authored Sep 9, 2024
1 parent 034764a commit e2d1e6e
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 90 deletions.
31 changes: 20 additions & 11 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,59 @@ Note that this plugin cannot be used in combination with Kong [upstreams](https:
## Plugin configuration parameters

```lua
aws_assume_role_arn - ARN of the IAM role that the plugin will try to assume
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.
aws_assume_role_name -- Name of the role above.
type = "string"
required = true

aws_region - AWS region where your Lambda is deployed to
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)
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)
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`
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`
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.
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.
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
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.
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
Expand All @@ -77,6 +82,10 @@ If ***`override_target_host`*** is not specified and multiple Lambdas are used i

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:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local plugin_name = "aws-request-signing"
local package_name = "kong-" .. plugin_name
local package_version = "1.0.6"
local package_version = "1.0.7"
local rockspec_revision = "3"

local github_account_name = "LEGO"
Expand Down
80 changes: 53 additions & 27 deletions kong/plugins/aws-request-signing/handler.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
local sigv4 = require "kong.plugins.aws-request-signing.sigv4"
local sigv4 = require "kong.plugins.aws-request-signing.sigv4"

local kong = kong
local ngx = ngx
local error = error
local type = type
local json = require "cjson"
local kong = kong
local ngx = ngx
local error = error
local type = type
local json = require "cjson"

local IAM_CREDENTIALS_CACHE_KEY_PATTERN = "plugin.aws-request-signing.iam_role_temp_creds.%s"
local AWSLambdaSTS = {}
local AWSLambdaSTS = {}

local function fetch_aws_credentials(sts_conf)
local sts = require('kong.plugins.aws-request-signing.webidentity-sts-credentials')

local result, err =
sts.fetch_assume_role_credentials(sts_conf.RoleArn, sts_conf.RoleSessionName, sts_conf.WebIdentityToken)
sts.fetch_assume_role_credentials(sts_conf.RoleArn, sts_conf.RoleSessionName, sts_conf.WebIdentityToken)

if err then
return nil, err
Expand Down Expand Up @@ -63,17 +63,17 @@ local function get_iam_credentials(sts_conf, refresh, return_sts_error)

if err then
kong.log.err(err)
if(return_sts_error ~= nil and return_sts_error == true ) then
if (return_sts_error ~= nil and return_sts_error == true) then
local errJson = err:gsub("failed to get from node cache:", "")
local resError = json.decode(errJson)
return kong.response.exit(resError.sts_status, { message = resError.message, stsResponse = resError.sts_body })
else
return kong.response.exit(401, {message = generic_error})
return kong.response.exit(401, { message = generic_error })
end
end

if not iam_role_credentials
or (get_now() + 60) > iam_role_credentials.expiration then
or (get_now() + 60) > iam_role_credentials.expiration then
kong.cache:invalidate_local(iam_role_cred_cache_key)
iam_role_credentials, err = kong.cache:get(
iam_role_cred_cache_key,
Expand All @@ -83,12 +83,12 @@ local function get_iam_credentials(sts_conf, refresh, return_sts_error)
)
if err then
kong.log.err(err)
if(return_sts_error ~= nil and return_sts_error == true ) then
if (return_sts_error ~= nil and return_sts_error == true) then
local errJson = err:gsub("failed to get from node cache:", "")
local resError = json.decode(errJson)
return kong.response.exit(resError.sts_status, { message = resError.message, stsResponse = resError.sts_body })
else
return kong.response.exit(401, {message = generic_error})
return kong.response.exit(401, { message = generic_error })
end
end
kong.log.debug("expiring key , invalidated iam_cache and fetched fresh credentials!")
Expand All @@ -103,7 +103,6 @@ end
function AWSLambdaSTS:access(conf)
local service = kong.router.get_service()
local request_headers = kong.request.get_headers()
local final_host = conf.override_target_host or ngx.ctx.balancer_data.host

if service == nil then
kong.log.err("Unable to retrieve bound service!")
Expand All @@ -116,15 +115,42 @@ function AWSLambdaSTS:access(conf)
})
end

local target_altered = false

local balancer_host = ngx.ctx.balancer_data.host
local balancer_port = ngx.ctx.balancer_data.port
local signed_host = balancer_host
local signed_port = balancer_port

if balancer_host ~= service.host then
target_altered = true
end
if balancer_port ~= service.port then
target_altered = true
end


if conf.override_target_protocol then
kong.service.request.set_scheme(conf.override_target_protocol)
end
if conf.override_target_port and conf.override_target_host then
kong.service.set_target(conf.override_target_host, conf.override_target_port)
elseif conf.override_target_host then
kong.service.set_target(conf.override_target_host, service.port)
elseif conf.override_target_port then
kong.service.set_target(final_host, conf.override_target_port)

local perform_override = true
if conf.use_altered_target and target_altered then
perform_override = false
end

if perform_override then
if conf.override_target_port and conf.override_target_host then
signed_host = conf.override_target_host
signed_port = conf.override_target_port
kong.service.set_target(conf.override_target_host, conf.override_target_port)
elseif conf.override_target_host then
signed_host = conf.override_target_host
kong.service.set_target(conf.override_target_host, signed_port)
elseif conf.override_target_port then
signed_port = conf.override_target_port
kong.service.set_target(signed_host, conf.override_target_port)
end
end


Expand All @@ -135,12 +161,12 @@ function AWSLambdaSTS:access(conf)
}

local iam_role_credentials = get_iam_credentials(sts_conf, request_headers["x-sts-refresh"],
conf.return_aws_sts_error)
conf.return_aws_sts_error)

-- we only send those two headers for signing
-- we only send those headers for signing
local upstream_headers = {
host = final_host,
-- those will be nill thus we only pass the host on requests without body
host = signed_host,
-- those will be nil which means that we only pass the host on requests without body
["content-length"] = request_headers["content-length"],
["content-type"] = request_headers["content-type"]
}
Expand All @@ -165,8 +191,8 @@ function AWSLambdaSTS:access(conf)
headers = upstream_headers,
body = req_body,
path = ngx.var.upstream_uri,
host = final_host,
port = service.port,
host = signed_host,
port = signed_port,
query = kong.request.get_raw_query(),
access_key = iam_role_credentials.access_key,
secret_key = iam_role_credentials.secret_key,
Expand All @@ -189,6 +215,6 @@ function AWSLambdaSTS:access(conf)
end

AWSLambdaSTS.PRIORITY = 15
AWSLambdaSTS.VERSION = "1.0.6"
AWSLambdaSTS.VERSION = "1.0.7"

return AWSLambdaSTS
137 changes: 86 additions & 51 deletions kong/plugins/aws-request-signing/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,96 @@ return {
-- this plugin will only run within Nginx HTTP module
protocols = typedefs.protocols_http
},
{ config = {
type = "record",
fields = {
{ aws_assume_role_arn = {
type = "string",
encrypted = true, -- Kong Enterprise-exclusive feature, does nothing in Kong CE
required = true,
} },
{ aws_assume_role_name = {
type = "string",
encrypted = true, -- Kong Enterprise-exclusive feature, does nothing in Kong CE
required = true,
} },
{ aws_region = {
type = "string",
required = true,
} },
{ aws_service = {
type = "string",
required = true,
} },
{ override_target_host = {
type = "string",
not_match = "^https?://"
} },
{ override_target_port = {
type = "number"
} },
{ override_target_protocol = {
type = "string",
{
config = {
type = "record",
fields = {
{
aws_assume_role_arn = {
type = "string",
encrypted = true, -- Kong Enterprise-exclusive feature, does nothing in Kong CE
required = true,
}
},
{
aws_assume_role_name = {
type = "string",
encrypted = true, -- Kong Enterprise-exclusive feature, does nothing in Kong CE
required = true,
}
},
{
aws_region = {
type = "string",
required = true,
}
},
{
aws_service = {
type = "string",
required = true,
}
},
{
override_target_host = {
type = "string",
not_match = "^https?://"
}
},
{
override_target_port = {
type = "number"
}
},
{
override_target_protocol = {
type = "string",
one_of = {
"http",
"https",
},
} },
{ return_aws_sts_error = {
type = "boolean",
required = true,
default = false,
} },
{ sign_query = {
type = "boolean",
required = true,
default = false,
} },
{ preserve_auth_header = {
type = "boolean",
required = true,
default = true,
} },
{ preserve_auth_header_key = {
type = "string",
required = true,
default = "x-authorization",
} }
}
},
{
use_altered_target = {
type = "boolean",
required = true,
default = false,
description =
"Instructs the plugin to use the context target if its host or port were altered "..
" (by other plugins) during the signing, bypassing the override_target_host "..
"and override_target_port parameters. Works by comparing the service target parameters"..
" with the context target parameters. Ignored if the target was not altered."
}
},
{
return_aws_sts_error = {
type = "boolean",
required = true,
default = false,
}
},
{
sign_query = {
type = "boolean",
required = true,
default = false,
}
},
{
preserve_auth_header = {
type = "boolean",
required = true,
default = true,
}
},
{
preserve_auth_header_key = {
type = "string",
required = true,
default = "x-authorization",
}
}
}
},
}
Expand Down

0 comments on commit e2d1e6e

Please sign in to comment.