Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(aws-cloudfront-apigateway-lambda): require explicit authentication type #1044

Merged
merged 3 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ new CloudFrontToApiGatewayToLambda(this, 'test-cloudfront-apigateway-lambda', {
code: lambda.Code.fromAsset(`lambda`),
runtime: lambda.Runtime.NODEJS_16_X,
handler: 'index.handler'
}
},
apiGatewayProps: {
defaultMethodOptions: {
authorizationType: api.AuthorizationType.NONE
}
},
});
```

Expand All @@ -44,17 +49,28 @@ Python
from aws_solutions_constructs.aws_cloudfront_apigateway_lambda import CloudFrontToApiGatewayToLambda
from aws_cdk import (
aws_lambda as _lambda,
aws_apigateway as apigw,
Stack
)
from constructs import Construct

CloudFrontToApiGatewayToLambda(self, 'test-cloudfront-apigateway-lambda',
lambda_function_props=_lambda.FunctionProps(
code=_lambda.Code.from_asset('lambda'),
runtime=_lambda.Runtime.PYTHON_3_9,
handler='index.handler'
)
)
CloudFrontToApiGatewayToLambda(
self, 'CloudFrontApiGatewayToLambda',
lambda_function_props=_lambda.FunctionProps(
runtime=_lambda.Runtime.PYTHON_3_7,
code=_lambda.Code.from_asset('lambda'),
handler='hello.handler',
),
# NOTE - we use RestApiProps here because the actual type, LambdaRestApiProps requires
# the handler function which does not yet exist. As RestApiProps is a subset of of LambdaRestApiProps
# (although does not *extend* that interface) this works fine when the props object reaches the
# underlying TypeScript code that implements Constructs
api_gateway_props=apigw.RestApiProps(
default_method_options=apigw.MethodOptions(
authorization_type=apigw.AuthorizationType.NONE
)
)
)
```

Java
Expand All @@ -66,25 +82,33 @@ import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.lambda.*;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awsconstructs.services.cloudfrontapigatewaylambda.*;

new CloudFrontToApiGatewayToLambda(this, "test-cloudfront-apigateway-lambda",
new CloudFrontToApiGatewayToLambdaProps.Builder()
.lambdaFunctionProps(new FunctionProps.Builder()
.runtime(Runtime.NODEJS_16_X)
.code(Code.fromAsset("lambda"))
.handler("index.handler")
import software.amazon.awsconstructs.services.cloudfrontapigatewaylambda.CloudFrontToApiGatewayToLambdaProps;

new CloudFrontToApiGatewayToLambda(this, "ApiGatewayToLambdaPattern", new CloudFrontToApiGatewayToLambdaProps.Builder()
.lambdaFunctionProps(new FunctionProps.Builder()
.runtime(Runtime.NODEJS_16_X) // execution environment
.code(Code.fromAsset("lambda")) // code loaded from the `lambda` directory (under root, next to `src`)
.handler("hello.handler") // file is `hello`, function is `handler`
.build())
// NOTE - we use RestApiProps here because the actual type, LambdaRestApiProps requires
// the handler function which does not yet exist. As RestApiProps is a subset of of LambdaRestApiProps
// (although does not *extend* that interface) this works fine when the props object reaches the
// underlying TypeScript code that implements Constructs
.apiGatewayProps(new RestApiProps.Builder()
.defaultMethodOptions(new MethodOptions.Builder()
.authorizationType(AuthorizationType.NONE)
.build())
.build());
.build())
.build());
```


## Pattern Construct Props

| **Name** | **Type** | **Description** |
|:-------------|:----------------|-----------------|
|existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.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/v2/docs/aws-cdk-lib.aws_lambda.FunctionProps.html)|Optional user provided props to override the default props for the Lambda function.|
|apiGatewayProps?|[`api.LambdaRestApiProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApiProps.html)|Optional user provided props to override the default props for API Gateway|
|apiGatewayProps?|[`api.LambdaRestApiProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApiProps.html)|User provided props to override the default props for the API Gateway. As of release 2.48.0, clients must include this property with `defaultMethodOptions: { authorizationType: string }` specified. See Issue1043 in the github repo https://github.com/awslabs/aws-solutions-constructs/issues/1043 |
|cloudFrontDistributionProps?|[`cloudfront.DistributionProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.DistributionProps.html)|Optional user provided props to override the default props for CloudFront Distribution|
|insertHttpSecurityHeaders?|`boolean`|Optional user provided props to turn on/off the automatic injection of best practice HTTP security headers in all responses from CloudFront|
| responseHeadersPolicyProps? | [`cloudfront.ResponseHeadersPolicyProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.ResponseHeadersPolicyProps.html) | Optional user provided configuration that cloudfront applies to all http responses. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ export interface CloudFrontToApiGatewayToLambdaProps {
*/
readonly lambdaFunctionProps?: lambda.FunctionProps
/**
* Optional user provided props to override the default props for the API Gateway.
* User provided props to override the default props for the API Gateway. As of release
* 2.48.0, clients must include this property with defaultMethodOptions: { authorizationType: string } specified.
* See Issue1043 in the github repo https://github.com/awslabs/aws-solutions-constructs/issues/1043
*
* @default - Default props are used
* @default - defaultMethodOptions/authorizationType is required, for other, unspecified values the
* default props are used
*/
readonly apiGatewayProps?: api.LambdaRestApiProps | any
readonly apiGatewayProps: api.LambdaRestApiProps | any
/**
* Optional user provided props to override the default props
*
Expand Down Expand Up @@ -106,6 +109,14 @@ export class CloudFrontToApiGatewayToLambda extends Construct {
super(scope, id);
defaults.CheckLambdaProps(props);
// CheckCloudFrontProps() is called by internal aws-cloudfront-apigateway construct
if (!props.apiGatewayProps?.defaultMethodOptions?.authorizationType) {
defaults.printWarning('As of v2.48.0, apiGatewayProps.defaultMethodOptions.authorizationType is\
required. To update your instantiation call, add the following to your CloudFrontToApiGatewayToLambdaProps argument\
\n\napiGatewayProps: { defaultMethodOptions: { authorizationType: api.AuthorizationType.NONE }},\n\nSee Issue1043 for an explanation.');
throw new Error('As of v2.48.0, an explicit authorization type is required for CloudFront/API Gateway patterns');
} else if (props.apiGatewayProps.defaultMethodOptions.authorizationType === "AWS_IAM") {
throw new Error('Amazon API Gateway Rest APIs integrated with Amazon CloudFront do not support AWS_IAM authorization');
}

// All our tests are based upon this behavior being on, so we're setting
// context here rather than assuming the client will set it
Expand All @@ -116,27 +127,17 @@ export class CloudFrontToApiGatewayToLambda extends Construct {
lambdaFunctionProps: props.lambdaFunctionProps
});

const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps);
// We can't default to IAM authentication with a CloudFront distribution, so
// we'll instruct core to not use any default auth to avoid override warnings
const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(this,
this.lambdaFunction,
props.apiGatewayProps,
props.logGroupProps,
false);
this.apiGateway = regionalLambdaRestApiResponse.api;
this.apiGatewayCloudWatchRole = regionalLambdaRestApiResponse.role;
this.apiGatewayLogGroup = regionalLambdaRestApiResponse.group;

this.apiGateway.methods.forEach((apiMethod) => {
// Override the API Gateway Authorization Type from AWS_IAM to NONE
const child = apiMethod.node.findChild('Resource') as api.CfnMethod;
if (child.authorizationType === 'AWS_IAM') {
child.addPropertyOverride('AuthorizationType', 'NONE');

defaults.addCfnSuppressRules(apiMethod, [
{
id: 'W59',
reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication`
},
]);

}
});

const apiCloudfront: CloudFrontToApiGateway = new CloudFrontToApiGateway(this, 'CloudFrontToApiGateway', {
existingApiGatewayObj: this.apiGateway,
cloudFrontDistributionProps: props.cloudFrontDistributionProps,
Expand Down
Loading