diff --git a/core/lambda_ngx_apis.conf b/core/lambda_ngx_apis.conf index 23e1278..5a21061 100644 --- a/core/lambda_ngx_apis.conf +++ b/core/lambda_ngx_apis.conf @@ -6,42 +6,14 @@ location /aws/credentials/retrieval { # js_fetch_trusted_certificate /etc/ssl/certs/Amazon_Root_CA_1.pem; } -location @lambda { - internal; - # Don't allow any headers from the client - we don't want them messing - # with Lambda at all. - proxy_pass_request_headers off; - - # Enable passing of the server name through TLS Server Name Indication extension. - proxy_ssl_server_name on; - #proxy_ssl_name ${LAMBDA_SERVER}; - - # Set the Authorization header to the AWS Signatures credentials - proxy_set_header x-amz-date $awsDate; - proxy_set_header x-amz-content-sha256 $awsPayloadHash; +location @lambda_function_arn { + include "lambda/lambda_ngx_proxy.conf"; proxy_set_header Authorization $lambdaFunctionARNAuth; + proxy_pass $lambda_url$lambdaURI; +} - # Enable when security token is needed - proxy_set_header X-Amz-Security-Token $awsSessionToken; - - # Use keep alive connections in order to improve performance - proxy_http_version 1.1; - proxy_set_header Connection ''; - - # We strip off all of the AWS specific headers from the server so that - # there is nothing identifying the object as having originated in an - # object store. - js_header_filter lambdagateway.editHeaders; - - # Catch all errors from Lambda and sanitize them so that the user can't - # gain intelligence about the Lambda being proxied. - proxy_intercept_errors on; - - # Comment out this line to receive the error messages returned by Lambda - #error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404; - #error_page 404 @trailslashControl; - - #proxy_pass ${S3_SERVER_PROTO}://storage_urls$s3uri; - #proxy_pass ${LAMBDA_SERVER_PROTO}://lambda_urls$lambdaURI; - proxy_pass $lambda_host$lambdaURI; +location @lambda_function_url { + include "lambda/lambda_ngx_proxy.conf"; + proxy_set_header Authorization $lambdaFunctionURLAuth; + proxy_pass $lambda_url; } diff --git a/core/lambda_ngx_http.conf b/core/lambda_ngx_http.conf index 11fd4da..ce2b9ff 100644 --- a/core/lambda_ngx_http.conf +++ b/core/lambda_ngx_http.conf @@ -10,12 +10,13 @@ js_set $awsPayloadHash awssig4.awsHeaderPayloadHash; js_set $awsSessionToken awscredentials.sessionToken; js_set $lambdaFunctionARNAuth lambdagateway.lambdaFunctionARNAuth; js_set $lambdaFunctionURLAuth lambdagateway.lambdaFunctionURLAuth; +js_set $lambdaFunctionARNHost lambdagateway.lambdaFunctionARNHost; +js_set $lambdaPort lambdagateway.lambdaPort; +js_set $lambdaProto lambdagateway.lambdaProto; js_set $lambdaURI lambdagateway.lambdaURI; -js_set $lambdaHost lambdagateway.lambdaHost; +js_set $lambdaURL lambdagateway.lambdaURL; -map $host $lambda_host { - default $lambdaHost; -} +resolver 8.8.8.8; # Extracts only the path from the requested URI. This strips out all query # parameters and anchors in order to prevent extraneous data from being sent @@ -24,4 +25,19 @@ map $request_uri $uri_path { "~^(?P.*?)(\?.*)*$" $path; } -resolver 8.8.8.8; +# Add the endpoint & host of Lambda server when using AWS Lambda Function URL. +# Add the endpoint, and assign the value of $lambdaFunctionARNHost when using +# AWS Lambda Function ARN. +map $request_uri $lambda_host { + default $lambdaFunctionARNHost; + '/bar' 'it6io4wr54p5ngkzygs4okvdmq0keqhf.lambda-url.us-east-2.on.aws'; + '/2015-03-31/functions/foo/invocations' $lambdaFunctionARNHost; +} + +# Add the endpoint when using AWS Lambda Function URL. The default value is for +# the URL of AWS Lambda Function ARN. +map $request_uri $lambda_url { + default $lambdaProto://$lambda_host:$lambdaPort; + '/bar' $lambdaProto://$lambda_host/; +} + diff --git a/core/lambda_ngx_proxy.conf b/core/lambda_ngx_proxy.conf new file mode 100644 index 0000000..7fa79a9 --- /dev/null +++ b/core/lambda_ngx_proxy.conf @@ -0,0 +1,40 @@ +# +# +# + +internal; +# Don't allow any headers from the client - we don't want them messing +# with Lambda at all. +proxy_pass_request_headers off; + +# Enable passing of the server name through TLS Server Name Indication extension. +proxy_ssl_server_name on; +#proxy_ssl_name ${LAMBDA_SERVER}; + +# Set the Authorization header to the AWS Signatures credentials +proxy_set_header x-amz-date $awsDate; +proxy_set_header x-amz-content-sha256 $awsPayloadHash; + +# Enable when security token is needed +proxy_set_header X-Amz-Security-Token $awsSessionToken; + +# Use keep alive connections in order to improve performance +proxy_http_version 1.1; +proxy_set_header Connection ''; + +# We strip off all of the AWS specific headers from the server so that +# there is nothing identifying the object as having originated in an +# object store. +js_header_filter lambdagateway.editHeaders; + +# Catch all errors from Lambda and sanitize them so that the user can't +# gain intelligence about the Lambda being proxied. +proxy_intercept_errors on; + +# Comment out this line to receive the error messages returned by Lambda +#error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404; +#error_page 404 @trailslashControl; + +#proxy_pass ${S3_SERVER_PROTO}://storage_urls$s3uri; +#proxy_pass ${LAMBDA_SERVER_PROTO}://lambda_urls$lambdaURI; + diff --git a/core/lambdagateway.js b/core/lambdagateway.js index aac2102..3835593 100644 --- a/core/lambdagateway.js +++ b/core/lambdagateway.js @@ -58,7 +58,7 @@ function lambdaFunctionARNAuth(r) { * @returns {string} AWS authentication signature */ function lambdaFunctionURLAuth(r) { - const host = r.variables.lambda_func_host ? r.variables.lambda_func_host : ''; + const host = r.variables.lambda_host ? r.variables.lambda_host : ''; const region = process.env['LAMBDA_REGION']; const queryParams = ''; const credentials = awscred.readCredentials(r); @@ -72,12 +72,21 @@ function lambdaFunctionURLAuth(r) { } /** - * Redirects the request to the appropriate location. + * Redirects the request to the appropriate location of AWS Lambda Function ARN. * * @param r {Request} HTTP request object */ -function redirectToLambda(r) { - r.internalRedirect("@lambda"); +function redirectToLambdaFunctionARN(r) { + r.internalRedirect("@lambda_function_arn"); +} + +/** + * Redirects the request to the AWS Lambda Function URL. + * + * @param r {Request} HTTP request object + */ +function redirectToLambdaFunctionURL(r) { + r.internalRedirect("@lambda_function_url"); } /** @@ -94,21 +103,55 @@ function lambdaURI(r) { } /** - * Returns the Lambda host given the environment variables + * Returns the host of Lambda Function ARN + * + * @param r HTTP request + * @returns {string} host of Lambda Function ARN + */ +function lambdaFunctionARNHost(r) { + return process.env['LAMBDA_SERVER']; +} + +/** + * Returns the protocol of Lambda Function ARN/URL + * + * @param r HTTP request + * @returns {string} protocol of Lambda Function ARN/URL + */ +function lambdaProto(r) { + const proto = process.env['LAMBDA_SERVER_PROTO']; + utils.debug_log(r, 'AWS Lambda Server Protocol: ' + proto); + return proto; +} + +/** + * Returns the port of Lambda Function ARN/URL + * + * @param r HTTP request + * @returns {string} port of Lambda Function ARN/URL + */ +function lambdaPort(r) { + const port = process.env['LAMBDA_SERVER_PORT']; + utils.debug_log(r, 'AWS Lambda Server Port: ' + port); + return port; +} + +/** + * Returns the Lambda URL given the environment variables * * @param r HTTP request - * @returns {string} host for Lambda request + * @returns {string} URL for Lambda request */ -function lambdaHost(r) { +function lambdaURL(r) { const proto = process.env['LAMBDA_SERVER_PROTO']; const server = process.env['LAMBDA_SERVER']; const port = process.env['LAMBDA_SERVER_PORT']; - // Generate lambda host using env variables as the following example: + // Generate lambda URL using env variables as the following example: // "https://lambda.us-east-2.amazonaws.com"; - const host = `${proto}://${server}:${port}`; - utils.debug_log(r, 'AWS Lambda Request Host: ' + host); - return host; + const url = `${proto}://${server}:${port}`; + utils.debug_log(r, 'AWS Lambda Request URL: ' + url); + return url; } /** @@ -255,11 +298,15 @@ export default { awsHeaderDate, editHeaders, lambdaFunctionARNAuth, + lambdaFunctionARNHost, lambdaFunctionURLAuth, lambdaDate, - lambdaHost, + lambdaPort, + lambdaProto, lambdaURI, - redirectToLambda, + lambdaURL, + redirectToLambdaFunctionARN, + redirectToLambdaFunctionURL, trailslashControl, // These functions do not need to be exposed, but they are exposed so that // unit tests can run against them. diff --git a/examples/02-proxy-to-each-lambda-function/frontend.conf b/examples/02-proxy-to-each-lambda-function/frontend.conf index 36fc89f..907e54a 100644 --- a/examples/02-proxy-to-each-lambda-function/frontend.conf +++ b/examples/02-proxy-to-each-lambda-function/frontend.conf @@ -4,48 +4,22 @@ server { include "lambda/lambda_ngx_apis.conf"; listen 80; - # Example of all endpoint to be proxied to AWS Lambda Function ARN. + # Example of all endpoint to be proxied to all AWS Lambda Function ARNs. location / { auth_request /aws/credentials/retrieval; - js_content lambdagateway.redirectToLambda; + js_content lambdagateway.redirectToLambdaFunctionARN; } - # Example of a specific endpoint to be proxied to AWS Lambda Function ARN. + # Example of a specific endpoint to be proxied to an AWS Lambda Function ARN. location /2015-03-31/functions/foo/invocations { auth_request /aws/credentials/retrieval; - js_content lambdagateway.redirectToLambda; + js_content lambdagateway.redirectToLambdaFunctionARN; } # Example of a specific endpoint to be proxied to AWS Lambda Function URL. location /bar { auth_request /aws/credentials/retrieval; - - # Don't allow any headers from the client - proxy_pass_request_headers off; - - # Enable passing of the server name through TLS Server Name Indication extension. - proxy_ssl_server_name on; - set $lambda_func_host 'it6io4wr54p5ngkzygs4okvdmq0keqhf.lambda-url.us-east-2.on.aws'; - proxy_ssl_name $lambda_func_host; - - # Set the Authorization header to the AWS Signatures credentials - proxy_set_header x-amz-date $awsDate; - proxy_set_header x-amz-content-sha256 $awsPayloadHash; - proxy_set_header Authorization $lambdaFunctionURLAuth; - - # Enable when security token is needed - proxy_set_header X-Amz-Security-Token $awsSessionToken; - - # Use keep alive connections in order to improve performance - proxy_http_version 1.1; - proxy_set_header Connection ''; - - # We strip off all of the AWS specific headers from the server so that - # there is nothing identifying the object as having originated in an - # object store. - js_header_filter lambdagateway.editHeaders; - - proxy_pass https://$lambda_func_host/; + js_content lambdagateway.redirectToLambdaFunctionURL; } # Enable when debugging is needed