-
Notifications
You must be signed in to change notification settings - Fork 249
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
6,869 additions
and
10 deletions.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
source/patterns/@aws-solutions-constructs/aws-alb-lambda/.eslintignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
lib/*.js | ||
test/*.js | ||
*.d.ts | ||
coverage | ||
test/lambda/index.js |
16 changes: 16 additions & 0 deletions
16
source/patterns/@aws-solutions-constructs/aws-alb-lambda/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
lib/*.js | ||
test/*.js | ||
!test/lambda/* | ||
*.js.map | ||
*.d.ts | ||
node_modules | ||
*.generated.ts | ||
dist | ||
.jsii | ||
|
||
.LAST_BUILD | ||
.nyc_output | ||
coverage | ||
.nycrc | ||
.LAST_PACKAGE | ||
*.snk |
21 changes: 21 additions & 0 deletions
21
source/patterns/@aws-solutions-constructs/aws-alb-lambda/.npmignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Exclude typescript source and config | ||
*.ts | ||
tsconfig.json | ||
coverage | ||
.nyc_output | ||
*.tgz | ||
*.snk | ||
*.tsbuildinfo | ||
|
||
# Include javascript files and typescript declarations | ||
!*.js | ||
!*.d.ts | ||
|
||
# Exclude jsii outdir | ||
dist | ||
|
||
# Include .jsii | ||
!.jsii | ||
|
||
# Include .jsii | ||
!.jsii |
108 changes: 108 additions & 0 deletions
108
source/patterns/@aws-solutions-constructs/aws-alb-lambda/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# aws-route53-alb module | ||
<!--BEGIN STABILITY BANNER--> | ||
|
||
--- | ||
|
||
![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) | ||
|
||
> All classes are under active development and subject to non-backward compatible changes or removal in any | ||
> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. | ||
> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. | ||
--- | ||
<!--END STABILITY BANNER--> | ||
|
||
| **Reference Documentation**:| <span style="font-weight: normal">https://docs.aws.amazon.com/solutions/latest/constructs/</span>| | ||
|:-------------|:-------------| | ||
<div style="height:8px"></div> | ||
|
||
| **Language** | **Package** | | ||
|:-------------|-----------------| | ||
|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_alb_lambda`| | ||
|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-alb-lambda`| | ||
|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.alblambda`| | ||
|
||
This AWS Solutions Construct implements an an Application Load Balancer to an AWS Lambda function | ||
|
||
Here is a minimal deployable pattern definition in Typescript: | ||
|
||
``` typescript | ||
|
||
// Obtain a pre-existing certificate from your account | ||
const certificate = acm.Certificate.fromCertificateArn( | ||
scope, | ||
'existing-cert', | ||
"arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012" | ||
); | ||
const props: AlbToLambdaProps = { | ||
lambdaFunctionProps: { | ||
code: lambda.Code.fromAsset(`${__dirname}/lambda`), | ||
runtime: lambda.Runtime.NODEJS_12_X, | ||
handler: 'index.handler' | ||
}, | ||
listenerProps: { | ||
certificates: [ certificate ] | ||
}, | ||
publicApi: true | ||
}; | ||
new AlbToLambda(stack, 'new-construct', props); | ||
|
||
``` | ||
|
||
## Initializer | ||
|
||
``` text | ||
new AlbToLambda(scope: Construct, id: string, props: AlbToLambdaProps); | ||
``` | ||
|
||
_Parameters_ | ||
|
||
* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html) | ||
* id `string` | ||
* props [`AlbToLambdaProps`](#pattern-construct-props) | ||
|
||
## Pattern Construct Props | ||
|
||
| **Name** | **Type** | **Description** | | ||
|:-------------|:----------------|-----------------| | ||
| loadBalancerProps? | [elasticloadbalancingv2.ApplicationLoadBalancerProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancerProps.html) | Optional custom properties for a new loadBalancer. Providing both this and existingLoadBalancer is an error. This cannot specify a VPC, it will use the VPC in existingVpc or the VPC created by the construct. | | ||
| existingLoadBalancerObj? | [elasticloadbalancingv2.ApplicationLoadBalancer](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html) | Existing Application Load Balancer to incorporate into the construct architecture. Providing both this and loadBalancerProps is an error. The VPC containing this loadBalancer must match the VPC provided in existingVpc. | | ||
| listenerProps? | [ApplicationListenerProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationListenerProps.html) | | | ||
| targetProps? | [ApplicationTargetGroupProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationTargetGroupProps.html) | | | ||
| ruleProps? | [AddRuleProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.AddRuleProps.html) | | | ||
| vpcProps? | [ec2.VpcProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html) | Optional custom properties for a VPC the construct will create. This VPC will be used by the new ALB and any Private Hosted Zone the construct creates (that's why loadBalancerProps and privateHostedZoneProps can't include a VPC). Providing both this and existingVpc is an error. | | ||
|existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Existing instance of Lambda Function object, providing both this and `lambdaFunctionProps` will cause an error.| | ||
|lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user provided props to override the default props for the Lambda function.| | ||
| existingVpc? | [ec2.IVpc](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | An existing VPC in which to deploy the construct. Providing both this and vpcProps is an error. If the client provides an existing load balancer and/or existing Private Hosted Zone, those constructs must exist in this VPC. | | ||
| logAccessLogs? | boolean| Whether to turn on Access Logs for the Application Load Balancer. Uses an S3 bucket with associated storage costs.Enabling Access Logging is a best practice. default - true | | ||
| loggingBucketProps? | [s3.BucketProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html) | Optional properties to customize the bucket used to store the ALB Access Logs. Supplying this and setting logAccessLogs to false is an error. @default - none | | ||
| publicApi | boolean | Whether the construct is deploying a private or public API. This has implications for the VPC and ALB. | | ||
|
||
## Pattern Properties | ||
|
||
| **Name** | **Type** | **Description** | | ||
|:-------------|:----------------|-----------------| | ||
| vpc | [ec2.IVpc](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | The VPC used by the construct (whether created by the construct or providedb by the client) | | ||
| loadBalancer | [elasticloadbalancingv2.ApplicationLoadBalancer](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html) | The Load Balancer used by the construct (whether created by the construct or providedb by the client) | | ||
|
||
## Default settings | ||
|
||
Out of the box implementation of the Construct without any override will set the following defaults: | ||
|
||
### Application Load Balancer | ||
* Creates or configures an Application Load Balancer with: | ||
* Required listeners | ||
* New target group with routing rules if appropriate | ||
|
||
### AWS Lambda Function | ||
* Configure limited privilege access IAM role for Lambda function | ||
* Enable reusing connections with Keep-Alive for NodeJs Lambda function | ||
* Enable X-Ray Tracing | ||
* Set Environment Variables | ||
* AWS_NODEJS_CONNECTION_REUSE_ENABLED (for Node 10.x and higher functions) | ||
|
||
## Architecture | ||
![Architecture Diagram](architecture.png) | ||
|
||
*** | ||
© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
Binary file added
BIN
+63.5 KB
source/patterns/@aws-solutions-constructs/aws-alb-lambda/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
198 changes: 198 additions & 0 deletions
198
source/patterns/@aws-solutions-constructs/aws-alb-lambda/lib/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/** | ||
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance | ||
* with the License. A copy of the License is located at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES | ||
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions | ||
* and limitations under the License. | ||
*/ | ||
|
||
import * as elb from "@aws-cdk/aws-elasticloadbalancingv2"; | ||
import * as ec2 from "@aws-cdk/aws-ec2"; | ||
import * as s3 from "@aws-cdk/aws-s3"; | ||
import * as lambda from "@aws-cdk/aws-lambda"; | ||
import { Construct } from "@aws-cdk/core"; | ||
import * as defaults from "@aws-solutions-constructs/core"; | ||
import { CfnListener, CfnTargetGroup } from "@aws-cdk/aws-elasticloadbalancingv2"; | ||
|
||
export interface AlbToLambdaProps { | ||
readonly loadBalancerProps?: elb.ApplicationLoadBalancerProps | any; | ||
readonly existingLoadBalancerObj?: elb.ApplicationLoadBalancer; | ||
|
||
/** | ||
* Existing instance of Lambda Function object, providing both this and `lambdaFunctionProps` will cause an error. | ||
* | ||
* @default - None | ||
*/ | ||
readonly existingLambdaObj?: lambda.Function; | ||
/** | ||
* User provided props to override the default props for the Lambda function. | ||
* | ||
* @default - Default props are used | ||
*/ | ||
readonly lambdaFunctionProps?: lambda.FunctionProps; | ||
|
||
readonly listenerProps?: elb.ApplicationListenerProps | any; | ||
|
||
readonly targetProps?: elb.ApplicationTargetGroupProps; | ||
readonly ruleProps?: elb.AddRuleProps; | ||
|
||
readonly vpcProps?: ec2.VpcProps; | ||
readonly existingVpc?: ec2.IVpc; | ||
/** | ||
* Whether to turn on Access Logs for the Application Load Balancer. Uses an S3 bucket | ||
* with associated storage costs. Enabling Access Logging is a best practice. | ||
* | ||
* @default - true | ||
*/ | ||
readonly logAlbAccessLogs?: boolean, | ||
/** | ||
* Optional properties to customize the bucket used to store the ALB Access | ||
* Logs. Supplying this and setting logAccessLogs to false is an error. | ||
* | ||
* @default - none | ||
*/ | ||
readonly albLoggingBucketProps?: s3.BucketProps, | ||
|
||
readonly publicApi: boolean; | ||
} | ||
|
||
export class AlbToLambda extends Construct { | ||
public readonly loadBalancer: elb.ApplicationLoadBalancer; | ||
public readonly vpc: ec2.IVpc; | ||
public readonly lambdaFunction: lambda.Function; | ||
public readonly listener: elb.ApplicationListener; | ||
|
||
constructor(scope: Construct, id: string, props: AlbToLambdaProps) { | ||
super(scope, id); | ||
defaults.CheckProps(props); | ||
|
||
if (props.listenerProps?.certificateArns) { | ||
throw new Error('certificateArns is deprecated. Please supply certificates using props.listenerProps.certificates'); | ||
} | ||
|
||
if ( | ||
(props.existingLoadBalancerObj && (props.existingLoadBalancerObj.listeners.length === 0) || !props.existingLoadBalancerObj) | ||
&& !props.listenerProps | ||
) { | ||
throw new Error( | ||
"When adding the first listener and target to a load balancer, listenerProps must be specified and include at least a certificate or protocol: HTTP" | ||
); | ||
} | ||
|
||
if ( | ||
((props.existingLoadBalancerObj) && (props.existingLoadBalancerObj.listeners.length > 0)) && | ||
props.listenerProps | ||
) { | ||
throw new Error( | ||
"This load balancer already has a listener, listenerProps may not be specified" | ||
); | ||
} | ||
|
||
if (((props.existingLoadBalancerObj) && (props.existingLoadBalancerObj.listeners.length > 0)) && !props.ruleProps) { | ||
throw new Error( | ||
"When adding a second target to an existing listener, there must be rules provided" | ||
); | ||
} | ||
|
||
// Check construct specific invalid inputs | ||
if (props.existingLoadBalancerObj && !props.existingVpc) { | ||
throw new Error( | ||
"An existing ALB already exists in a VPC, that VPC must be provided in props.existingVpc for the rest of the construct to use." | ||
); | ||
} | ||
|
||
if ( props.existingLoadBalancerObj ) { | ||
defaults.printWarning( | ||
"The public/private property of an exisng ALB must match the props.publicApi setting provided." | ||
); | ||
} | ||
|
||
// Obtain VPC for construct (existing or created) | ||
// Determine all the resources to use (existing or launch new) | ||
if (props.existingVpc) { | ||
this.vpc = props.existingVpc; | ||
} else { | ||
this.vpc = defaults.buildVpc(scope, { | ||
defaultVpcProps: props.publicApi | ||
? defaults.DefaultPublicPrivateVpcProps() | ||
: defaults.DefaultIsolatedVpcProps(), | ||
userVpcProps: props.vpcProps, | ||
constructVpcProps: props.publicApi | ||
? undefined | ||
: { enableDnsHostnames: true, enableDnsSupport: true, }, | ||
}); | ||
} | ||
|
||
this.loadBalancer = defaults.ObtainAlb( | ||
this, | ||
id, | ||
this.vpc, | ||
props.publicApi, | ||
props.existingLoadBalancerObj, | ||
props.loadBalancerProps, | ||
props.logAlbAccessLogs, | ||
props.albLoggingBucketProps | ||
); | ||
|
||
// Obtain Lambda function for construct (existing or created) | ||
this.lambdaFunction = defaults.buildLambdaFunction(this, { | ||
existingLambdaObj: props.existingLambdaObj, | ||
lambdaFunctionProps: props.lambdaFunctionProps, | ||
vpc: this.vpc, | ||
}); | ||
|
||
if (this.loadBalancer.listeners.length === 0) { | ||
// This is a new listener, we need to create it along with the default target | ||
const newTargetGroup = defaults.CreateLambdaTargetGroup(this, 'first-tg', this.lambdaFunction, props.targetProps); | ||
this.listener = defaults.AddListener( | ||
this, | ||
this.loadBalancer, | ||
newTargetGroup, | ||
props.listenerProps | ||
); | ||
// Testing occasionally caused a TargetGroup not found error, this | ||
// code ensures the Group will be complete before the Listener tries | ||
// to access it. | ||
const newListener = this.listener.node.defaultChild as CfnListener; | ||
const cfnTargetGroup = newTargetGroup.node.defaultChild as CfnTargetGroup; | ||
newListener.addDependsOn(cfnTargetGroup); | ||
} else { | ||
// We're adding a target to an existing listener. If this.loadBalancer.listeners.length | ||
// is >0, then this.loadBalancer was set from existingLoadBalancer | ||
this.listener = GetActiveListener(this.loadBalancer.listeners); | ||
defaults.AddTarget( | ||
this, | ||
defaults.CreateLambdaTargetGroup( | ||
this, | ||
`tg${this.loadBalancer.listeners.length}`, | ||
this.lambdaFunction, | ||
props.targetProps | ||
), | ||
this.listener, | ||
props.ruleProps | ||
); | ||
} | ||
} | ||
} | ||
|
||
function GetActiveListener(listeners: elb.ApplicationListener[]): elb.ApplicationListener { | ||
let listener: elb.ApplicationListener; | ||
|
||
if (listeners.length === 1 ) { | ||
listener = listeners[0]; | ||
} else { | ||
const correctListener = listeners.find(i => (i.node.children[0] as elb.CfnListener).protocol === "HTTPS"); | ||
if (correctListener) { | ||
listener = correctListener; | ||
} else { | ||
// This line should be unreachable | ||
throw new Error(`Two listeners in the ALB, but neither are HTTPS`); | ||
} | ||
} | ||
return listener; | ||
} |
Oops, something went wrong.