@aws/nx-plugin 0.102.0 → 0.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-THIRD-PARTY +207 -0
- package/package.json +1 -1
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +510 -1
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +437 -0
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +522 -1
- package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +6 -0
- package/src/utils/api-constructs/files/cdk/core/api/rest/rest-api.ts.template +99 -1
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +20 -0
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +115 -0
|
@@ -405,6 +405,12 @@ export interface TestApiProps<
|
|
|
405
405
|
identity: {
|
|
406
406
|
userPool: IUserPool;
|
|
407
407
|
};
|
|
408
|
+
/**
|
|
409
|
+
* Whether to enable AWS WAFv2 with the default managed ruleset on the API's default stage.
|
|
410
|
+
*
|
|
411
|
+
* @default true
|
|
412
|
+
*/
|
|
413
|
+
enableWaf?: boolean;
|
|
408
414
|
}
|
|
409
415
|
|
|
410
416
|
/**
|
|
@@ -813,6 +819,12 @@ export interface TestApiProps<
|
|
|
813
819
|
* Map of operation names to their API Gateway integrations
|
|
814
820
|
*/
|
|
815
821
|
integrations: TIntegrations;
|
|
822
|
+
/**
|
|
823
|
+
* Whether to enable AWS WAFv2 with the default managed ruleset on the API's default stage.
|
|
824
|
+
*
|
|
825
|
+
* @default true
|
|
826
|
+
*/
|
|
827
|
+
enableWaf?: boolean;
|
|
816
828
|
}
|
|
817
829
|
|
|
818
830
|
/**
|
|
@@ -1960,7 +1972,13 @@ import {
|
|
|
1960
1972
|
IResource,
|
|
1961
1973
|
Stage,
|
|
1962
1974
|
} from 'aws-cdk-lib/aws-apigateway';
|
|
1963
|
-
import { IAspect } from 'aws-cdk-lib';
|
|
1975
|
+
import { IAspect, RemovalPolicy } from 'aws-cdk-lib';
|
|
1976
|
+
import {
|
|
1977
|
+
CfnLoggingConfiguration,
|
|
1978
|
+
CfnWebACL,
|
|
1979
|
+
CfnWebACLAssociation,
|
|
1980
|
+
} from 'aws-cdk-lib/aws-wafv2';
|
|
1981
|
+
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
|
|
1964
1982
|
import { RuntimeConfig } from '../runtime-config.js';
|
|
1965
1983
|
import {
|
|
1966
1984
|
ApiIntegrations,
|
|
@@ -1991,6 +2009,14 @@ export interface RestApiProps<
|
|
|
1991
2009
|
* Map of integration keys to their API Gateway integrations
|
|
1992
2010
|
*/
|
|
1993
2011
|
readonly integrations: TIntegrations;
|
|
2012
|
+
/**
|
|
2013
|
+
* Whether to enable AWS WAFv2 with the default managed ruleset
|
|
2014
|
+
* (AWSManagedRulesCommonRuleSet and AWSManagedRulesKnownBadInputsRuleSet)
|
|
2015
|
+
* and associate it with the API's default stage.
|
|
2016
|
+
*
|
|
2017
|
+
* @default true
|
|
2018
|
+
*/
|
|
2019
|
+
readonly enableWaf?: boolean;
|
|
1994
2020
|
}
|
|
1995
2021
|
|
|
1996
2022
|
/**
|
|
@@ -2014,6 +2040,9 @@ export class RestApi<
|
|
|
2014
2040
|
/** Map of integration keys to their API Gateway integrations */
|
|
2015
2041
|
public readonly integrations: TIntegrations;
|
|
2016
2042
|
|
|
2043
|
+
/** The WAFv2 Web ACL associated with the API's default stage, if WAF is enabled */
|
|
2044
|
+
public readonly webAcl?: CfnWebACL;
|
|
2045
|
+
|
|
2017
2046
|
constructor(
|
|
2018
2047
|
scope: Construct,
|
|
2019
2048
|
id: string,
|
|
@@ -2021,6 +2050,7 @@ export class RestApi<
|
|
|
2021
2050
|
apiName,
|
|
2022
2051
|
operations,
|
|
2023
2052
|
integrations,
|
|
2053
|
+
enableWaf = true,
|
|
2024
2054
|
...props
|
|
2025
2055
|
}: RestApiProps<TIntegrations, TOperation>,
|
|
2026
2056
|
) {
|
|
@@ -2030,6 +2060,86 @@ export class RestApi<
|
|
|
2030
2060
|
// Create the API Gateway REST API
|
|
2031
2061
|
this.api = new _RestApi(this, 'Api', props);
|
|
2032
2062
|
|
|
2063
|
+
if (enableWaf) {
|
|
2064
|
+
this.webAcl = new CfnWebACL(this, 'WebAcl', {
|
|
2065
|
+
defaultAction: { allow: {} },
|
|
2066
|
+
scope: 'REGIONAL',
|
|
2067
|
+
visibilityConfig: {
|
|
2068
|
+
cloudWatchMetricsEnabled: true,
|
|
2069
|
+
metricName: \`\${apiName}WebAcl\`,
|
|
2070
|
+
sampledRequestsEnabled: true,
|
|
2071
|
+
},
|
|
2072
|
+
rules: [
|
|
2073
|
+
{
|
|
2074
|
+
name: 'CRSRule',
|
|
2075
|
+
priority: 0,
|
|
2076
|
+
statement: {
|
|
2077
|
+
managedRuleGroupStatement: {
|
|
2078
|
+
name: 'AWSManagedRulesCommonRuleSet',
|
|
2079
|
+
vendorName: 'AWS',
|
|
2080
|
+
// Count instead of Block: the CRS 8 KB body limit is too restrictive for most APIs.
|
|
2081
|
+
ruleActionOverrides: [
|
|
2082
|
+
{
|
|
2083
|
+
name: 'SizeRestrictions_BODY',
|
|
2084
|
+
actionToUse: { count: {} },
|
|
2085
|
+
},
|
|
2086
|
+
],
|
|
2087
|
+
},
|
|
2088
|
+
},
|
|
2089
|
+
visibilityConfig: {
|
|
2090
|
+
cloudWatchMetricsEnabled: true,
|
|
2091
|
+
metricName: \`\${apiName}WebAcl-CRS\`,
|
|
2092
|
+
sampledRequestsEnabled: true,
|
|
2093
|
+
},
|
|
2094
|
+
overrideAction: {
|
|
2095
|
+
none: {},
|
|
2096
|
+
},
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
name: 'KnownBadInputsRule',
|
|
2100
|
+
priority: 1,
|
|
2101
|
+
statement: {
|
|
2102
|
+
managedRuleGroupStatement: {
|
|
2103
|
+
name: 'AWSManagedRulesKnownBadInputsRuleSet',
|
|
2104
|
+
vendorName: 'AWS',
|
|
2105
|
+
},
|
|
2106
|
+
},
|
|
2107
|
+
visibilityConfig: {
|
|
2108
|
+
cloudWatchMetricsEnabled: true,
|
|
2109
|
+
metricName: \`\${apiName}WebAcl-KnownBadInputs\`,
|
|
2110
|
+
sampledRequestsEnabled: true,
|
|
2111
|
+
},
|
|
2112
|
+
overrideAction: {
|
|
2113
|
+
none: {},
|
|
2114
|
+
},
|
|
2115
|
+
},
|
|
2116
|
+
],
|
|
2117
|
+
});
|
|
2118
|
+
|
|
2119
|
+
new CfnWebACLAssociation(this, 'WebAclAssociation', {
|
|
2120
|
+
resourceArn: this.api.deploymentStage.stageArn,
|
|
2121
|
+
webAclArn: this.webAcl.attrArn,
|
|
2122
|
+
});
|
|
2123
|
+
|
|
2124
|
+
// Send WAF request logs to CloudWatch. The log group name must start with
|
|
2125
|
+
// \`aws-waf-logs-\` to satisfy the WAFv2 logging destination requirement.
|
|
2126
|
+
const wafLogGroup = new LogGroup(this, 'WebAclLogs', {
|
|
2127
|
+
logGroupName: \`aws-waf-logs-\${apiName}-\${this.node.addr.slice(-8)}\`,
|
|
2128
|
+
retention: RetentionDays.ONE_MONTH,
|
|
2129
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
2130
|
+
});
|
|
2131
|
+
suppressRules(
|
|
2132
|
+
wafLogGroup,
|
|
2133
|
+
['CKV_AWS_158'],
|
|
2134
|
+
'Using default CloudWatch log encryption for WAF logs',
|
|
2135
|
+
);
|
|
2136
|
+
|
|
2137
|
+
new CfnLoggingConfiguration(this, 'WebAclLoggingConfig', {
|
|
2138
|
+
resourceArn: this.webAcl.attrArn,
|
|
2139
|
+
logDestinationConfigs: [wafLogGroup.logGroupArn],
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2033
2143
|
suppressRules(
|
|
2034
2144
|
this.api,
|
|
2035
2145
|
['CKV_AWS_120'],
|
|
@@ -2172,6 +2282,12 @@ export interface TestApiProps<
|
|
|
2172
2282
|
* Map of operation names to their API Gateway integrations
|
|
2173
2283
|
*/
|
|
2174
2284
|
integrations: TIntegrations;
|
|
2285
|
+
/**
|
|
2286
|
+
* Whether to enable AWS WAFv2 with the default managed ruleset on the API's default stage.
|
|
2287
|
+
*
|
|
2288
|
+
* @default true
|
|
2289
|
+
*/
|
|
2290
|
+
enableWaf?: boolean;
|
|
2175
2291
|
}
|
|
2176
2292
|
|
|
2177
2293
|
/**
|
|
@@ -4692,6 +4808,10 @@ terraform {
|
|
|
4692
4808
|
source = "hashicorp/aws"
|
|
4693
4809
|
version = "~> 6.33"
|
|
4694
4810
|
}
|
|
4811
|
+
random = {
|
|
4812
|
+
source = "hashicorp/random"
|
|
4813
|
+
version = "~> 3.1"
|
|
4814
|
+
}
|
|
4695
4815
|
}
|
|
4696
4816
|
}
|
|
4697
4817
|
|
|
@@ -4720,6 +4840,12 @@ variable "stage_auto_deploy" {
|
|
|
4720
4840
|
default = true
|
|
4721
4841
|
}
|
|
4722
4842
|
|
|
4843
|
+
variable "enable_waf" {
|
|
4844
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset (AWSManagedRulesCommonRuleSet and AWSManagedRulesKnownBadInputsRuleSet). The Web ACL is created here and associated with the stage in the consuming module."
|
|
4845
|
+
type = bool
|
|
4846
|
+
default = true
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4723
4849
|
# CORS Configuration
|
|
4724
4850
|
|
|
4725
4851
|
variable "cors_allow_headers" {
|
|
@@ -4801,6 +4927,106 @@ resource "aws_api_gateway_gateway_response" "cors_5xx" {
|
|
|
4801
4927
|
}
|
|
4802
4928
|
}
|
|
4803
4929
|
|
|
4930
|
+
resource "aws_wafv2_web_acl" "api_waf" {
|
|
4931
|
+
#checkov:skip=CKV2_AWS_31:Logging configuration is defined below in aws_wafv2_web_acl_logging_configuration.api_waf_logging; Checkov does not resolve the separate resource
|
|
4932
|
+
count = var.enable_waf ? 1 : 0
|
|
4933
|
+
|
|
4934
|
+
name = "\${var.api_name}-waf"
|
|
4935
|
+
scope = "REGIONAL"
|
|
4936
|
+
|
|
4937
|
+
default_action {
|
|
4938
|
+
allow {}
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
rule {
|
|
4942
|
+
name = "CRSRule"
|
|
4943
|
+
priority = 0
|
|
4944
|
+
|
|
4945
|
+
override_action {
|
|
4946
|
+
none {}
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
statement {
|
|
4950
|
+
managed_rule_group_statement {
|
|
4951
|
+
name = "AWSManagedRulesCommonRuleSet"
|
|
4952
|
+
vendor_name = "AWS"
|
|
4953
|
+
|
|
4954
|
+
# Count instead of Block: the CRS 8 KB body limit is too restrictive for most APIs.
|
|
4955
|
+
rule_action_override {
|
|
4956
|
+
name = "SizeRestrictions_BODY"
|
|
4957
|
+
action_to_use {
|
|
4958
|
+
count {}
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4964
|
+
visibility_config {
|
|
4965
|
+
cloudwatch_metrics_enabled = true
|
|
4966
|
+
metric_name = "\${var.api_name}WebAcl-CRS"
|
|
4967
|
+
sampled_requests_enabled = true
|
|
4968
|
+
}
|
|
4969
|
+
}
|
|
4970
|
+
|
|
4971
|
+
rule {
|
|
4972
|
+
name = "KnownBadInputsRule"
|
|
4973
|
+
priority = 1
|
|
4974
|
+
|
|
4975
|
+
override_action {
|
|
4976
|
+
none {}
|
|
4977
|
+
}
|
|
4978
|
+
|
|
4979
|
+
statement {
|
|
4980
|
+
managed_rule_group_statement {
|
|
4981
|
+
name = "AWSManagedRulesKnownBadInputsRuleSet"
|
|
4982
|
+
vendor_name = "AWS"
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
|
|
4986
|
+
visibility_config {
|
|
4987
|
+
cloudwatch_metrics_enabled = true
|
|
4988
|
+
metric_name = "\${var.api_name}WebAcl-KnownBadInputs"
|
|
4989
|
+
sampled_requests_enabled = true
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
visibility_config {
|
|
4994
|
+
cloudwatch_metrics_enabled = true
|
|
4995
|
+
metric_name = "\${var.api_name}WebAcl"
|
|
4996
|
+
sampled_requests_enabled = true
|
|
4997
|
+
}
|
|
4998
|
+
|
|
4999
|
+
tags = var.tags
|
|
5000
|
+
|
|
5001
|
+
lifecycle {
|
|
5002
|
+
create_before_destroy = true
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
|
|
5006
|
+
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
5007
|
+
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
5008
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
5009
|
+
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
5010
|
+
count = var.enable_waf ? 1 : 0
|
|
5011
|
+
|
|
5012
|
+
name = "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}"
|
|
5013
|
+
retention_in_days = 30
|
|
5014
|
+
tags = var.tags
|
|
5015
|
+
}
|
|
5016
|
+
|
|
5017
|
+
resource "random_id" "waf_log_suffix" {
|
|
5018
|
+
count = var.enable_waf ? 1 : 0
|
|
5019
|
+
byte_length = 4
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
5023
|
+
count = var.enable_waf ? 1 : 0
|
|
5024
|
+
|
|
5025
|
+
log_destination_configs = [aws_cloudwatch_log_group.api_waf_logs[0].arn]
|
|
5026
|
+
resource_arn = aws_wafv2_web_acl.api_waf[0].arn
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
|
|
4804
5030
|
# Outputs
|
|
4805
5031
|
|
|
4806
5032
|
output "api_id" {
|
|
@@ -4828,6 +5054,11 @@ output "api_root_resource_id" {
|
|
|
4828
5054
|
value = aws_api_gateway_rest_api.rest_api.root_resource_id
|
|
4829
5055
|
}
|
|
4830
5056
|
|
|
5057
|
+
output "waf_web_acl_arn" {
|
|
5058
|
+
description = "ARN of the WAFv2 Web ACL associated with the API, or null if WAF is disabled"
|
|
5059
|
+
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
5060
|
+
}
|
|
5061
|
+
|
|
4831
5062
|
# Note: Stage and deployment outputs are provided by the consuming module
|
|
4832
5063
|
|
|
4833
5064
|
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
|
|
@@ -4889,6 +5120,13 @@ variable "cors_allow_origins" {
|
|
|
4889
5120
|
default = ["*"]
|
|
4890
5121
|
}
|
|
4891
5122
|
|
|
5123
|
+
# WAF Configuration
|
|
5124
|
+
variable "enable_waf" {
|
|
5125
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset on the API stage"
|
|
5126
|
+
type = bool
|
|
5127
|
+
default = true
|
|
5128
|
+
}
|
|
5129
|
+
|
|
4892
5130
|
# Tags
|
|
4893
5131
|
variable "tags" {
|
|
4894
5132
|
description = "Tags to apply to all resources"
|
|
@@ -4918,6 +5156,9 @@ module "rest_api" {
|
|
|
4918
5156
|
stage_name = "prod"
|
|
4919
5157
|
stage_auto_deploy = true
|
|
4920
5158
|
|
|
5159
|
+
# WAF Configuration
|
|
5160
|
+
enable_waf = var.enable_waf
|
|
5161
|
+
|
|
4921
5162
|
# CORS Configuration
|
|
4922
5163
|
cors_allow_headers = var.cors_allow_headers
|
|
4923
5164
|
cors_allow_methods = var.cors_allow_methods
|
|
@@ -4927,6 +5168,15 @@ module "rest_api" {
|
|
|
4927
5168
|
tags = var.tags
|
|
4928
5169
|
}
|
|
4929
5170
|
|
|
5171
|
+
resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
5172
|
+
count = var.enable_waf ? 1 : 0
|
|
5173
|
+
|
|
5174
|
+
resource_arn = aws_api_gateway_stage.api_stage.arn
|
|
5175
|
+
web_acl_arn = module.rest_api.waf_web_acl_arn
|
|
5176
|
+
|
|
5177
|
+
depends_on = [aws_api_gateway_stage.api_stage]
|
|
5178
|
+
}
|
|
5179
|
+
|
|
4930
5180
|
# Lambda function
|
|
4931
5181
|
resource "aws_lambda_function" "api_lambda" {
|
|
4932
5182
|
#checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
|
|
@@ -5143,6 +5393,7 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
5143
5393
|
#checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
|
|
5144
5394
|
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
5145
5395
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
5396
|
+
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
5146
5397
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
5147
5398
|
rest_api_id = module.rest_api.api_id
|
|
5148
5399
|
stage_name = "prod"
|
|
@@ -5340,6 +5591,10 @@ terraform {
|
|
|
5340
5591
|
source = "hashicorp/aws"
|
|
5341
5592
|
version = "~> 6.33"
|
|
5342
5593
|
}
|
|
5594
|
+
random = {
|
|
5595
|
+
source = "hashicorp/random"
|
|
5596
|
+
version = "~> 3.1"
|
|
5597
|
+
}
|
|
5343
5598
|
}
|
|
5344
5599
|
}
|
|
5345
5600
|
|
|
@@ -5368,6 +5623,12 @@ variable "stage_auto_deploy" {
|
|
|
5368
5623
|
default = true
|
|
5369
5624
|
}
|
|
5370
5625
|
|
|
5626
|
+
variable "enable_waf" {
|
|
5627
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset (AWSManagedRulesCommonRuleSet and AWSManagedRulesKnownBadInputsRuleSet). The Web ACL is created here and associated with the stage in the consuming module."
|
|
5628
|
+
type = bool
|
|
5629
|
+
default = true
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5371
5632
|
# CORS Configuration
|
|
5372
5633
|
|
|
5373
5634
|
variable "cors_allow_headers" {
|
|
@@ -5449,6 +5710,106 @@ resource "aws_api_gateway_gateway_response" "cors_5xx" {
|
|
|
5449
5710
|
}
|
|
5450
5711
|
}
|
|
5451
5712
|
|
|
5713
|
+
resource "aws_wafv2_web_acl" "api_waf" {
|
|
5714
|
+
#checkov:skip=CKV2_AWS_31:Logging configuration is defined below in aws_wafv2_web_acl_logging_configuration.api_waf_logging; Checkov does not resolve the separate resource
|
|
5715
|
+
count = var.enable_waf ? 1 : 0
|
|
5716
|
+
|
|
5717
|
+
name = "\${var.api_name}-waf"
|
|
5718
|
+
scope = "REGIONAL"
|
|
5719
|
+
|
|
5720
|
+
default_action {
|
|
5721
|
+
allow {}
|
|
5722
|
+
}
|
|
5723
|
+
|
|
5724
|
+
rule {
|
|
5725
|
+
name = "CRSRule"
|
|
5726
|
+
priority = 0
|
|
5727
|
+
|
|
5728
|
+
override_action {
|
|
5729
|
+
none {}
|
|
5730
|
+
}
|
|
5731
|
+
|
|
5732
|
+
statement {
|
|
5733
|
+
managed_rule_group_statement {
|
|
5734
|
+
name = "AWSManagedRulesCommonRuleSet"
|
|
5735
|
+
vendor_name = "AWS"
|
|
5736
|
+
|
|
5737
|
+
# Count instead of Block: the CRS 8 KB body limit is too restrictive for most APIs.
|
|
5738
|
+
rule_action_override {
|
|
5739
|
+
name = "SizeRestrictions_BODY"
|
|
5740
|
+
action_to_use {
|
|
5741
|
+
count {}
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
|
|
5747
|
+
visibility_config {
|
|
5748
|
+
cloudwatch_metrics_enabled = true
|
|
5749
|
+
metric_name = "\${var.api_name}WebAcl-CRS"
|
|
5750
|
+
sampled_requests_enabled = true
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5753
|
+
|
|
5754
|
+
rule {
|
|
5755
|
+
name = "KnownBadInputsRule"
|
|
5756
|
+
priority = 1
|
|
5757
|
+
|
|
5758
|
+
override_action {
|
|
5759
|
+
none {}
|
|
5760
|
+
}
|
|
5761
|
+
|
|
5762
|
+
statement {
|
|
5763
|
+
managed_rule_group_statement {
|
|
5764
|
+
name = "AWSManagedRulesKnownBadInputsRuleSet"
|
|
5765
|
+
vendor_name = "AWS"
|
|
5766
|
+
}
|
|
5767
|
+
}
|
|
5768
|
+
|
|
5769
|
+
visibility_config {
|
|
5770
|
+
cloudwatch_metrics_enabled = true
|
|
5771
|
+
metric_name = "\${var.api_name}WebAcl-KnownBadInputs"
|
|
5772
|
+
sampled_requests_enabled = true
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5775
|
+
|
|
5776
|
+
visibility_config {
|
|
5777
|
+
cloudwatch_metrics_enabled = true
|
|
5778
|
+
metric_name = "\${var.api_name}WebAcl"
|
|
5779
|
+
sampled_requests_enabled = true
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5782
|
+
tags = var.tags
|
|
5783
|
+
|
|
5784
|
+
lifecycle {
|
|
5785
|
+
create_before_destroy = true
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
|
|
5789
|
+
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
5790
|
+
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
5791
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
5792
|
+
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
5793
|
+
count = var.enable_waf ? 1 : 0
|
|
5794
|
+
|
|
5795
|
+
name = "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}"
|
|
5796
|
+
retention_in_days = 30
|
|
5797
|
+
tags = var.tags
|
|
5798
|
+
}
|
|
5799
|
+
|
|
5800
|
+
resource "random_id" "waf_log_suffix" {
|
|
5801
|
+
count = var.enable_waf ? 1 : 0
|
|
5802
|
+
byte_length = 4
|
|
5803
|
+
}
|
|
5804
|
+
|
|
5805
|
+
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
5806
|
+
count = var.enable_waf ? 1 : 0
|
|
5807
|
+
|
|
5808
|
+
log_destination_configs = [aws_cloudwatch_log_group.api_waf_logs[0].arn]
|
|
5809
|
+
resource_arn = aws_wafv2_web_acl.api_waf[0].arn
|
|
5810
|
+
}
|
|
5811
|
+
|
|
5812
|
+
|
|
5452
5813
|
# Outputs
|
|
5453
5814
|
|
|
5454
5815
|
output "api_id" {
|
|
@@ -5476,6 +5837,11 @@ output "api_root_resource_id" {
|
|
|
5476
5837
|
value = aws_api_gateway_rest_api.rest_api.root_resource_id
|
|
5477
5838
|
}
|
|
5478
5839
|
|
|
5840
|
+
output "waf_web_acl_arn" {
|
|
5841
|
+
description = "ARN of the WAFv2 Web ACL associated with the API, or null if WAF is disabled"
|
|
5842
|
+
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
5843
|
+
}
|
|
5844
|
+
|
|
5479
5845
|
# Note: Stage and deployment outputs are provided by the consuming module
|
|
5480
5846
|
|
|
5481
5847
|
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
|
|
@@ -5527,6 +5893,13 @@ variable "cors_allow_origins" {
|
|
|
5527
5893
|
default = ["*"]
|
|
5528
5894
|
}
|
|
5529
5895
|
|
|
5896
|
+
# WAF Configuration
|
|
5897
|
+
variable "enable_waf" {
|
|
5898
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset on the API stage"
|
|
5899
|
+
type = bool
|
|
5900
|
+
default = true
|
|
5901
|
+
}
|
|
5902
|
+
|
|
5530
5903
|
# Tags
|
|
5531
5904
|
variable "tags" {
|
|
5532
5905
|
description = "Tags to apply to all resources"
|
|
@@ -5556,6 +5929,9 @@ module "rest_api" {
|
|
|
5556
5929
|
stage_name = "prod"
|
|
5557
5930
|
stage_auto_deploy = true
|
|
5558
5931
|
|
|
5932
|
+
# WAF Configuration
|
|
5933
|
+
enable_waf = var.enable_waf
|
|
5934
|
+
|
|
5559
5935
|
# CORS Configuration
|
|
5560
5936
|
cors_allow_headers = var.cors_allow_headers
|
|
5561
5937
|
cors_allow_methods = var.cors_allow_methods
|
|
@@ -5565,6 +5941,15 @@ module "rest_api" {
|
|
|
5565
5941
|
tags = var.tags
|
|
5566
5942
|
}
|
|
5567
5943
|
|
|
5944
|
+
resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
5945
|
+
count = var.enable_waf ? 1 : 0
|
|
5946
|
+
|
|
5947
|
+
resource_arn = aws_api_gateway_stage.api_stage.arn
|
|
5948
|
+
web_acl_arn = module.rest_api.waf_web_acl_arn
|
|
5949
|
+
|
|
5950
|
+
depends_on = [aws_api_gateway_stage.api_stage]
|
|
5951
|
+
}
|
|
5952
|
+
|
|
5568
5953
|
# Lambda function
|
|
5569
5954
|
resource "aws_lambda_function" "api_lambda" {
|
|
5570
5955
|
#checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
|
|
@@ -5772,6 +6157,7 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
5772
6157
|
#checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
|
|
5773
6158
|
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
5774
6159
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
6160
|
+
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
5775
6161
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
5776
6162
|
rest_api_id = module.rest_api.api_id
|
|
5777
6163
|
stage_name = "prod"
|
|
@@ -5980,6 +6366,10 @@ terraform {
|
|
|
5980
6366
|
source = "hashicorp/aws"
|
|
5981
6367
|
version = "~> 6.33"
|
|
5982
6368
|
}
|
|
6369
|
+
random = {
|
|
6370
|
+
source = "hashicorp/random"
|
|
6371
|
+
version = "~> 3.1"
|
|
6372
|
+
}
|
|
5983
6373
|
}
|
|
5984
6374
|
}
|
|
5985
6375
|
|
|
@@ -6008,6 +6398,12 @@ variable "stage_auto_deploy" {
|
|
|
6008
6398
|
default = true
|
|
6009
6399
|
}
|
|
6010
6400
|
|
|
6401
|
+
variable "enable_waf" {
|
|
6402
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset (AWSManagedRulesCommonRuleSet and AWSManagedRulesKnownBadInputsRuleSet). The Web ACL is created here and associated with the stage in the consuming module."
|
|
6403
|
+
type = bool
|
|
6404
|
+
default = true
|
|
6405
|
+
}
|
|
6406
|
+
|
|
6011
6407
|
# CORS Configuration
|
|
6012
6408
|
|
|
6013
6409
|
variable "cors_allow_headers" {
|
|
@@ -6089,6 +6485,106 @@ resource "aws_api_gateway_gateway_response" "cors_5xx" {
|
|
|
6089
6485
|
}
|
|
6090
6486
|
}
|
|
6091
6487
|
|
|
6488
|
+
resource "aws_wafv2_web_acl" "api_waf" {
|
|
6489
|
+
#checkov:skip=CKV2_AWS_31:Logging configuration is defined below in aws_wafv2_web_acl_logging_configuration.api_waf_logging; Checkov does not resolve the separate resource
|
|
6490
|
+
count = var.enable_waf ? 1 : 0
|
|
6491
|
+
|
|
6492
|
+
name = "\${var.api_name}-waf"
|
|
6493
|
+
scope = "REGIONAL"
|
|
6494
|
+
|
|
6495
|
+
default_action {
|
|
6496
|
+
allow {}
|
|
6497
|
+
}
|
|
6498
|
+
|
|
6499
|
+
rule {
|
|
6500
|
+
name = "CRSRule"
|
|
6501
|
+
priority = 0
|
|
6502
|
+
|
|
6503
|
+
override_action {
|
|
6504
|
+
none {}
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
statement {
|
|
6508
|
+
managed_rule_group_statement {
|
|
6509
|
+
name = "AWSManagedRulesCommonRuleSet"
|
|
6510
|
+
vendor_name = "AWS"
|
|
6511
|
+
|
|
6512
|
+
# Count instead of Block: the CRS 8 KB body limit is too restrictive for most APIs.
|
|
6513
|
+
rule_action_override {
|
|
6514
|
+
name = "SizeRestrictions_BODY"
|
|
6515
|
+
action_to_use {
|
|
6516
|
+
count {}
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
|
|
6522
|
+
visibility_config {
|
|
6523
|
+
cloudwatch_metrics_enabled = true
|
|
6524
|
+
metric_name = "\${var.api_name}WebAcl-CRS"
|
|
6525
|
+
sampled_requests_enabled = true
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
|
|
6529
|
+
rule {
|
|
6530
|
+
name = "KnownBadInputsRule"
|
|
6531
|
+
priority = 1
|
|
6532
|
+
|
|
6533
|
+
override_action {
|
|
6534
|
+
none {}
|
|
6535
|
+
}
|
|
6536
|
+
|
|
6537
|
+
statement {
|
|
6538
|
+
managed_rule_group_statement {
|
|
6539
|
+
name = "AWSManagedRulesKnownBadInputsRuleSet"
|
|
6540
|
+
vendor_name = "AWS"
|
|
6541
|
+
}
|
|
6542
|
+
}
|
|
6543
|
+
|
|
6544
|
+
visibility_config {
|
|
6545
|
+
cloudwatch_metrics_enabled = true
|
|
6546
|
+
metric_name = "\${var.api_name}WebAcl-KnownBadInputs"
|
|
6547
|
+
sampled_requests_enabled = true
|
|
6548
|
+
}
|
|
6549
|
+
}
|
|
6550
|
+
|
|
6551
|
+
visibility_config {
|
|
6552
|
+
cloudwatch_metrics_enabled = true
|
|
6553
|
+
metric_name = "\${var.api_name}WebAcl"
|
|
6554
|
+
sampled_requests_enabled = true
|
|
6555
|
+
}
|
|
6556
|
+
|
|
6557
|
+
tags = var.tags
|
|
6558
|
+
|
|
6559
|
+
lifecycle {
|
|
6560
|
+
create_before_destroy = true
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
|
|
6564
|
+
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
6565
|
+
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
6566
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
6567
|
+
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
6568
|
+
count = var.enable_waf ? 1 : 0
|
|
6569
|
+
|
|
6570
|
+
name = "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}"
|
|
6571
|
+
retention_in_days = 30
|
|
6572
|
+
tags = var.tags
|
|
6573
|
+
}
|
|
6574
|
+
|
|
6575
|
+
resource "random_id" "waf_log_suffix" {
|
|
6576
|
+
count = var.enable_waf ? 1 : 0
|
|
6577
|
+
byte_length = 4
|
|
6578
|
+
}
|
|
6579
|
+
|
|
6580
|
+
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
6581
|
+
count = var.enable_waf ? 1 : 0
|
|
6582
|
+
|
|
6583
|
+
log_destination_configs = [aws_cloudwatch_log_group.api_waf_logs[0].arn]
|
|
6584
|
+
resource_arn = aws_wafv2_web_acl.api_waf[0].arn
|
|
6585
|
+
}
|
|
6586
|
+
|
|
6587
|
+
|
|
6092
6588
|
# Outputs
|
|
6093
6589
|
|
|
6094
6590
|
output "api_id" {
|
|
@@ -6116,6 +6612,11 @@ output "api_root_resource_id" {
|
|
|
6116
6612
|
value = aws_api_gateway_rest_api.rest_api.root_resource_id
|
|
6117
6613
|
}
|
|
6118
6614
|
|
|
6615
|
+
output "waf_web_acl_arn" {
|
|
6616
|
+
description = "ARN of the WAFv2 Web ACL associated with the API, or null if WAF is disabled"
|
|
6617
|
+
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
6618
|
+
}
|
|
6619
|
+
|
|
6119
6620
|
# Note: Stage and deployment outputs are provided by the consuming module
|
|
6120
6621
|
|
|
6121
6622
|
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
|
|
@@ -6167,6 +6668,13 @@ variable "cors_allow_origins" {
|
|
|
6167
6668
|
default = ["*"]
|
|
6168
6669
|
}
|
|
6169
6670
|
|
|
6671
|
+
# WAF Configuration
|
|
6672
|
+
variable "enable_waf" {
|
|
6673
|
+
description = "Whether to enable AWS WAFv2 with the default managed ruleset on the API stage"
|
|
6674
|
+
type = bool
|
|
6675
|
+
default = true
|
|
6676
|
+
}
|
|
6677
|
+
|
|
6170
6678
|
# Tags
|
|
6171
6679
|
variable "tags" {
|
|
6172
6680
|
description = "Tags to apply to all resources"
|
|
@@ -6196,6 +6704,9 @@ module "rest_api" {
|
|
|
6196
6704
|
stage_name = "prod"
|
|
6197
6705
|
stage_auto_deploy = true
|
|
6198
6706
|
|
|
6707
|
+
# WAF Configuration
|
|
6708
|
+
enable_waf = var.enable_waf
|
|
6709
|
+
|
|
6199
6710
|
# CORS Configuration
|
|
6200
6711
|
cors_allow_headers = var.cors_allow_headers
|
|
6201
6712
|
cors_allow_methods = var.cors_allow_methods
|
|
@@ -6205,6 +6716,15 @@ module "rest_api" {
|
|
|
6205
6716
|
tags = var.tags
|
|
6206
6717
|
}
|
|
6207
6718
|
|
|
6719
|
+
resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
6720
|
+
count = var.enable_waf ? 1 : 0
|
|
6721
|
+
|
|
6722
|
+
resource_arn = aws_api_gateway_stage.api_stage.arn
|
|
6723
|
+
web_acl_arn = module.rest_api.waf_web_acl_arn
|
|
6724
|
+
|
|
6725
|
+
depends_on = [aws_api_gateway_stage.api_stage]
|
|
6726
|
+
}
|
|
6727
|
+
|
|
6208
6728
|
# Lambda function
|
|
6209
6729
|
resource "aws_lambda_function" "api_lambda" {
|
|
6210
6730
|
#checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
|
|
@@ -6414,6 +6934,7 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
6414
6934
|
#checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
|
|
6415
6935
|
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
6416
6936
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
6937
|
+
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
6417
6938
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
6418
6939
|
rest_api_id = module.rest_api.api_id
|
|
6419
6940
|
stage_name = "prod"
|