feat(plugins): aws lambda serverless#5594
Conversation
5331ab3 to
a8e6fd8
Compare
|
depends on: #5616 |
| local plugin_name, plugin_version, priority = "azure-functions", 0.1, -1900 | ||
|
|
||
| local schema = { | ||
| local azure_authz_schema = { |
There was a problem hiding this comment.
we are developing a new feature "aws lambda serverless", so we should not update azure-functions.lua, it is a different thing.
one for one thing.
| local resty_sha256 = require("resty.sha256") | ||
|
|
||
|
|
||
| local plugin_name, plugin_version, priority = "aws-lambda", 0.1, -1899 |
There was a problem hiding this comment.
bad style
good style:
local plugin_name = "aws-lambda"
local plugin_version = 0.1
local priority = -1899
| return kSigning | ||
| end | ||
|
|
||
| local aws_authz_schema = { |
There was a problem hiding this comment.
I think we use schema is fine, the file name is aws-lamda
There was a problem hiding this comment.
This is not the complete schema, rather it's the part of the schema (handling the plugin specific authorization details).
see:
| service = { | ||
| type = "string", | ||
| default = "execute-api", | ||
| description = "The service that is receiving the request" |
There was a problem hiding this comment.
The service or the service?
we should use the same style with others.
|
|
||
| local ngx = ngx | ||
| local pairs = pairs | ||
| local concat = table.concat |
There was a problem hiding this comment.
bad name, I think we should add a prefix tab_
| local ngx = ngx | ||
| local pairs = pairs | ||
| local concat = table.concat | ||
| local sort = table.sort |
| end | ||
|
|
||
|
|
||
| return require("apisix.plugins.serverless.generic-upstream")(plugin_name, |
There was a problem hiding this comment.
it is not easy to read.
another style:
local serverless_obj = require("apisix.plugins.serverless.generic-upstream")
local aws_obj = serverless_obj.new({
name = plugin_name,
version = plugin_version,
priority = priority,
... ...
})There was a problem hiding this comment.
Nice. Updated accordingly
| GET /apisix/admin/plugins/list | ||
| --- response_body_like eval | ||
| qr/\["real-ip","client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","ldap-auth","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","datadog","echo","http-logger","skywalking-logger","google-cloud-logging","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","azure-functions","openwhisk","serverless-post-function","ext-plugin-post-req"\]/ | ||
| qr/\["real-ip","client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","ldap-auth","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","datadog","echo","http-logger","skywalking-logger","google-cloud-logging","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","aws-lambda","azure-functions","openwhisk","serverless-post-function","ext-plugin-post-req"\]/ |
There was a problem hiding this comment.
Can we split this into multiple lines? We can do it in the next PR.
There was a problem hiding this comment.
Yes, It's time to modify this to another easy-to-read format.
| if k ~= "connection" then | ||
| signed_headers[#signed_headers+1] = k | ||
| -- strip starting and trailing spaces including strip multiple spaces into single space | ||
| canonical_headers[k] = v:gsub("^%s+", ""):gsub("%s+$", "") |
There was a problem hiding this comment.
| headers["X-Amz-Date"] = amzdate | ||
|
|
||
| -- computing canonical uri | ||
| local canonical_uri = params.path:gsub("//", "/") |
There was a problem hiding this comment.
Can we use pl.path to do part of the normalized work?
https://refined-github-html-preview.kidonng.workers.dev/lunarmodules/Penlight/raw/master/docs/libraries/pl.path.html#normpath
| local serverless_obj = require("apisix.plugins.serverless.generic-upstream") | ||
|
|
||
| return serverless_obj(plugin_name, | ||
| plugin_version, |
| local tab_sort = table.sort | ||
| local os = os | ||
| local hmac = require("resty.hmac") | ||
| local hexencode = require("resty.string").to_hex |
There was a problem hiding this comment.
Can we use underscore style for function name?
| return hexencode(digest) | ||
| end | ||
|
|
||
| local function getSignatureKey(key, datestamp, region, service) |
| "Hello, apisix!" | ||
| ``` | ||
|
|
||
| For requests where the mode of communication between the client and the Apache APISIX gateway is HTTP/2, the example looks like ( make sure you are running APISIX agent with `enable_http2: true` for a port in conf.yaml or uncomment port 9081 of `node_listen` field inside [config-default.yaml](../../../../conf/config-default.yaml) ) : |
There was a problem hiding this comment.
Better to use config-default.yaml directly, since people may read the doc on the doc's website. Please fix the azure-functions' doc too.
|
|
||
| ## How To Enable | ||
|
|
||
| The following is an example of how to enable the aws-lambda faas plugin for a specific route URI. Calling the apisix route uri will make an invocation to the lambda function uri (the new upstream). We are assuming your cloud function is already up and running. |
There was a problem hiding this comment.
Please use APISIX route instead of apisix route. Need to fix other similar places.
There was a problem hiding this comment.
Okay. Got it. Thanks for letting me know : )
|
@shuaijinchao @tzssangglass pls review when you have time |
|
|
||
| ## How To Enable | ||
|
|
||
| The following is an example of how to enable the aws-lambda faas plugin for a specific route URI. Calling the apisix route uri will make an invocation to the lambda function uri (the new upstream). We are assuming your cloud function is already up and running. |
| GET /apisix/admin/plugins/list | ||
| --- response_body_like eval | ||
| qr/\["real-ip","client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","ldap-auth","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","datadog","echo","http-logger","skywalking-logger","google-cloud-logging","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","azure-functions","openwhisk","serverless-post-function","ext-plugin-post-req"\]/ | ||
| qr/\["real-ip","client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","ldap-auth","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","datadog","echo","http-logger","skywalking-logger","google-cloud-logging","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","aws-lambda","azure-functions","openwhisk","serverless-post-function","ext-plugin-post-req"\]/ |
There was a problem hiding this comment.
Yes, It's time to modify this to another easy-to-read format.
| | authorization.apikey | string | optional | | | Field inside _authorization_. The generate API Key to authorize requests to that endpoint of the aws gateway. | | | ||
| | authorization.iam | object | optional | | | Field inside _authorization_. AWS IAM role based authorization, performed via aws v4 request signing. See schema details below ([here](#iam-authorization-schema)). | | | ||
| | timeout | integer | optional | 3000 | [100,...] | Proxy request timeout in milliseconds. | | ||
| | ssl_verify | boolean | optional | true | true/false | If enabled performs SSL verification of the server. | |
There was a problem hiding this comment.
if the ssl_verify is true, do we need to specify a certificate?
There was a problem hiding this comment.
If it is generated from any trusted public CA, we don't have to specify the certificate of the CA as along the hierarchy chain eventually it will point to the root CA. But that's not the case with self signed certs. In that case, simply ssl_verify:false will do or there is an option to specify the CA certificate file. see ref below
The optional ssl_verify argument takes a Lua boolean value to control whether to perform SSL verification. When set to true, the server certificate will be verified according to the CA certificates specified by the lua_ssl_trusted_certificate directive. You may also need to adjust the lua_ssl_verify_depth directive to control how deep we should follow along the certificate chain. Also, when the ssl_verify argument is true and the server_name argument is also specified, the latter will be used to validate the server name in the server certificate.
| --- response_headers | ||
| Content-Length: 19 |
There was a problem hiding this comment.
why check the Content-Length
There was a problem hiding this comment.
Hi, thanks for the review.
It just checks if the headers that are being received from upstream lambda are being forwarded by the plugin. Not just Content-Length specifically but all headers from the mock HTTP endpoint
| if k ~= "connection" then | ||
| signed_headers[#signed_headers+1] = k |
There was a problem hiding this comment.
I don't understand here, do we just need to skip connection?
There was a problem hiding this comment.
First of all, I would like to specify, we are not tampering connection header for the request that is being sent to the lambda.
This section performs aws v4 request signing with aws iam secret key. As per the aws docs, to have the authenticity of the request (and to validate that the request has not been modified by any third party over the wire) it suggests generating hash digest from as many headers as we can (however host and x-amz-date is mandatory). In real-world testing what i have found that aws gateway doesn't include the connection header value (keep-alive, close) for hash calculation. That's why I simply omitted it as it never was any hard requirement.

What this PR does / why we need it:
create a route
With API key-based authorization
{ "plugins": { "aws-lambda": { "function_uri": "https://x9w6z07gb9.execute-api.us-east-1.amazonaws.com/default/test-apisix", "authorization": { "apikey": "<apikey>" }, "ssl_verify":false } }, "uri": "/aws" }With IAM v4 request signing
{ "plugins": { "aws-lambda": { "function_uri": "https://x9w6z07gb9.execute-api.us-east-1.amazonaws.com/default/test-apisix", "authorization": { "iam": { "accesskey": <accesskey>, "secretkey": <secretkey>, "aws_region": "us-east-1", "service": "execute-api" } }, "ssl_verify":false } }, "uri": "/aws" }Pre-submission checklist: