cdk-factory 0.9.11__tar.gz → 0.10.0__tar.gz
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.
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/PKG-INFO +1 -1
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/pyproject.toml +1 -1
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/run-tests.sh +10 -6
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/app.py +39 -8
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/auto_scaling.py +27 -0
- cdk_factory-0.10.0/src/cdk_factory/configurations/resources/cloudfront.py +124 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/ecs_service.py +12 -0
- cdk_factory-0.10.0/src/cdk_factory/configurations/resources/lambda_edge.py +92 -0
- cdk_factory-0.10.0/src/cdk_factory/configurations/resources/monitoring.py +74 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +51 -1
- cdk_factory-0.10.0/src/cdk_factory/lambdas/edge/ip_gate/handler.py +104 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/pipeline_factory.py +1 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +99 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/cloudfront/__init__.py +6 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +627 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +90 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/lambda_edge/__init__.py +6 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +217 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/monitoring/__init__.py +6 -0
- cdk_factory-0.10.0/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +492 -0
- cdk_factory-0.10.0/src/cdk_factory/version.py +1 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/workload/workload_factory.py +2 -0
- cdk_factory-0.9.11/src/cdk_factory/configurations/resources/cloudfront.py +0 -34
- cdk_factory-0.9.11/src/cdk_factory/version.py +0 -1
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/.gitignore +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/.windsurfrules +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/LICENSE +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/archive/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/archive/migrate_to_enhanced_ssm.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/examples/json-imports/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/examples/separate-api-gateway/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/examples/separate-api-gateway/config.json +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/examples/separate-api-gateway/lambda-stack.json +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/mypy.ini +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/publish_to_pypi.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/publish_to_pypi.sh +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/pysetup.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/pysetup.sh +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/requirements.dev.txt +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/requirements.tests.txt +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/requirements.txt +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/run-checks.sh +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/run-tests-clean-venv.sh +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/builds/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/cdk.json +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/cli.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/commands/command_loader.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/base_config.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/cdk_config.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/deployment.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/deployment_wave.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/devops.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/management.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/pipeline.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/_resources.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/cognito.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/docker.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/ecr.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/rds.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/route53.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/rum.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/s3.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/security_group.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/sqs.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/vpc.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/workload.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/istack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/lambdas/health_handler.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/path_utils.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/security/policies.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/security/roles.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/stage.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack/istack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_factory.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_module_loader.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_module_registry.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_modules.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/buckets/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecr/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/stack_base.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/templates/README.md +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/templates/app.py.template +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/templates/cdk.json.template +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/commandline_args.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/configuration_loader.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/docker_utilities.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/environment_services.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/file_operations.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/git_utilities.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utilities/os_execute.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
- {cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/handlers/test/handler.py +0 -0
|
@@ -24,15 +24,19 @@ echo "=================================="
|
|
|
24
24
|
if [ ! -d ".venv" ]; then
|
|
25
25
|
echo -e "${YELLOW}Creating virtual environment...${NC}"
|
|
26
26
|
python3 -m venv .venv
|
|
27
|
+
# Install dependencies
|
|
28
|
+
echo -e "${YELLOW}Installing dependencies...${NC}"
|
|
29
|
+
pip install -q -r requirements.dev.txt
|
|
30
|
+
pip install -q -r requirements.tests.txt
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# see if it's activated
|
|
34
|
+
if [ ! -f ".venv/bin/activate" ]; then
|
|
35
|
+
echo -e "${YELLOW}Activating virtual environment...${NC}"
|
|
36
|
+
source ./.venv/bin/activate
|
|
27
37
|
fi
|
|
28
38
|
|
|
29
|
-
echo -e "${YELLOW}Activating virtual environment...${NC}"
|
|
30
|
-
source ./.venv/bin/activate
|
|
31
39
|
|
|
32
|
-
# Install dependencies
|
|
33
|
-
echo -e "${YELLOW}Installing dependencies...${NC}"
|
|
34
|
-
pip install -q -r requirements.dev.txt
|
|
35
|
-
pip install -q -r requirements.tests.txt
|
|
36
40
|
|
|
37
41
|
# Check if pytest is installed in the virtual environment
|
|
38
42
|
if ! command -v pytest &> /dev/null; then
|
|
@@ -32,15 +32,12 @@ class CdkAppFactory:
|
|
|
32
32
|
config_path: str | None = None,
|
|
33
33
|
outdir: str | None = None,
|
|
34
34
|
add_env_context: bool = True,
|
|
35
|
-
auto_detect_project_root: bool = True,
|
|
36
|
-
is_pipeline: bool = False,
|
|
37
35
|
) -> None:
|
|
38
36
|
|
|
39
37
|
self.args = args or CommandlineArgs()
|
|
40
38
|
self.runtime_directory = runtime_directory
|
|
41
39
|
self.config_path: str | None = config_path
|
|
42
40
|
self.add_env_context = add_env_context
|
|
43
|
-
self._is_pipeline = is_pipeline
|
|
44
41
|
|
|
45
42
|
# Auto-detect runtime_directory if not provided
|
|
46
43
|
if not self.runtime_directory:
|
|
@@ -50,21 +47,26 @@ class CdkAppFactory:
|
|
|
50
47
|
# 1. Explicit outdir parameter (highest priority)
|
|
51
48
|
# 2. CDK_OUTDIR environment variable
|
|
52
49
|
# 3. Default: {runtime_directory}/cdk.out
|
|
53
|
-
|
|
50
|
+
|
|
54
51
|
supplied_outdir = outdir or (
|
|
55
52
|
self.args.outdir if hasattr(self.args, "outdir") else None
|
|
56
53
|
)
|
|
57
|
-
|
|
54
|
+
|
|
58
55
|
if supplied_outdir:
|
|
59
|
-
# Explicit outdir:
|
|
60
|
-
|
|
56
|
+
# Explicit outdir: if relative, resolve against runtime_directory
|
|
57
|
+
# If absolute, use as-is
|
|
58
|
+
if os.path.isabs(supplied_outdir):
|
|
59
|
+
self.outdir = supplied_outdir
|
|
60
|
+
else:
|
|
61
|
+
# Relative path: resolve against runtime_directory, not cwd
|
|
62
|
+
self.outdir = os.path.join(self.runtime_directory, supplied_outdir)
|
|
61
63
|
elif os.getenv("CDK_OUTDIR"):
|
|
62
64
|
# Environment variable override
|
|
63
65
|
self.outdir = os.path.abspath(os.getenv("CDK_OUTDIR"))
|
|
64
66
|
else:
|
|
65
67
|
# Default: cdk.out in runtime_directory
|
|
66
68
|
# This resolves correctly in both local and CodeBuild environments
|
|
67
|
-
self.outdir =
|
|
69
|
+
self.outdir = os.path.join(self.runtime_directory, "cdk.out")
|
|
68
70
|
|
|
69
71
|
# Clean and recreate directory for fresh synthesis
|
|
70
72
|
if os.path.exists(self.outdir):
|
|
@@ -126,6 +128,8 @@ class CdkAppFactory:
|
|
|
126
128
|
# Validate that the assembly directory exists and has files
|
|
127
129
|
self._validate_synth_output(assembly)
|
|
128
130
|
|
|
131
|
+
self._copy_cdk_out_to_project_root()
|
|
132
|
+
|
|
129
133
|
return assembly
|
|
130
134
|
|
|
131
135
|
def _validate_synth_output(self, assembly: CloudAssembly) -> None:
|
|
@@ -244,6 +248,33 @@ class CdkAppFactory:
|
|
|
244
248
|
# Priority 4: Fallback to runtime_directory
|
|
245
249
|
return str(current)
|
|
246
250
|
|
|
251
|
+
def _copy_cdk_out_to_project_root(self):
|
|
252
|
+
# Copy the cdk.out directory to the project root so it can be picked up by CodeBuild
|
|
253
|
+
# Source: the actual CDK output directory from the synthesis (e.g., /tmp/cdk-factory/cdk.out)
|
|
254
|
+
cdk_out_source = self.outdir
|
|
255
|
+
|
|
256
|
+
# raise Exception(f"cdk_out_source: {cdk_out_source}")
|
|
257
|
+
|
|
258
|
+
# Destination: project root (two directories up from devops/cdk-iac where this file lives)
|
|
259
|
+
project_root = os.getenv("CODEBUILD_SRC_DIR")
|
|
260
|
+
if not project_root:
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
cdk_out_dest = os.path.join(project_root, "cdk.out")
|
|
264
|
+
|
|
265
|
+
print(f"👉 Project root: {project_root}")
|
|
266
|
+
print(f"👉 CDK output source: {cdk_out_source}")
|
|
267
|
+
print(f"👉 CDK output destination: {cdk_out_dest}")
|
|
268
|
+
|
|
269
|
+
if os.path.exists(cdk_out_dest):
|
|
270
|
+
print("❌ CDK output directory already exists, skipping copy")
|
|
271
|
+
return
|
|
272
|
+
else:
|
|
273
|
+
print("✅ CDK output directory does not exist, copying")
|
|
274
|
+
|
|
275
|
+
shutil.copytree(cdk_out_source, cdk_out_dest)
|
|
276
|
+
print(f"✅ Copied CDK output to {cdk_out_dest}")
|
|
277
|
+
|
|
247
278
|
|
|
248
279
|
if __name__ == "__main__":
|
|
249
280
|
# deploy_test()
|
{cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/auto_scaling.py
RENAMED
|
@@ -148,3 +148,30 @@ class AutoScalingConfig(EnhancedBaseConfig):
|
|
|
148
148
|
def target_group_arns(self) -> List[str]:
|
|
149
149
|
"""Target group ARNs for the Auto Scaling Group"""
|
|
150
150
|
return self.__config.get("target_group_arns", [])
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def user_data_scripts(self) -> List[Dict[str, Any]]:
|
|
154
|
+
"""
|
|
155
|
+
User data scripts to inject from files.
|
|
156
|
+
Each script should have:
|
|
157
|
+
- type: 'file' or 'inline'
|
|
158
|
+
- path: path to script file (if type is 'file')
|
|
159
|
+
- content: script content (if type is 'inline')
|
|
160
|
+
- variables: dict of variables for substitution
|
|
161
|
+
"""
|
|
162
|
+
return self.__config.get("user_data_scripts", [])
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def iam_inline_policies(self) -> List[Dict[str, Any]]:
|
|
166
|
+
"""
|
|
167
|
+
IAM inline policies to attach to the instance role.
|
|
168
|
+
Each policy should have:
|
|
169
|
+
- name: policy name
|
|
170
|
+
- statements: list of IAM policy statements
|
|
171
|
+
"""
|
|
172
|
+
return self.__config.get("iam_inline_policies", [])
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def key_name(self) -> Optional[str]:
|
|
176
|
+
"""EC2 key pair name for SSH access"""
|
|
177
|
+
return self.__config.get("key_name")
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
from typing import Dict, List, Any, Optional
|
|
7
|
+
from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CloudFrontConfig(EnhancedBaseConfig):
|
|
11
|
+
"""
|
|
12
|
+
CloudFront Distribution Configuration
|
|
13
|
+
Supports both S3 origins (static sites) and custom origins (ALB, API Gateway, etc.)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, config: dict = None, deployment=None) -> None:
|
|
17
|
+
super().__init__(
|
|
18
|
+
config or {},
|
|
19
|
+
resource_type="cloudfront",
|
|
20
|
+
resource_name=config.get("name", "cloudfront") if config else "cloudfront"
|
|
21
|
+
)
|
|
22
|
+
self._config = config or {}
|
|
23
|
+
self._deployment = deployment
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def name(self) -> str:
|
|
27
|
+
"""Distribution name"""
|
|
28
|
+
return self._config.get("name", "cloudfront")
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def description(self) -> str:
|
|
32
|
+
"""Distribution description"""
|
|
33
|
+
return self._config.get("description", "CloudFront Distribution")
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def comment(self) -> str:
|
|
37
|
+
"""Distribution comment"""
|
|
38
|
+
return self._config.get("comment", "")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def enabled(self) -> bool:
|
|
42
|
+
"""Whether distribution is enabled"""
|
|
43
|
+
return self._config.get("enabled", True)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def aliases(self) -> List[str]:
|
|
47
|
+
"""Alternate domain names (CNAMEs)"""
|
|
48
|
+
return self._config.get("aliases", [])
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def price_class(self) -> str:
|
|
52
|
+
"""Price class for edge locations"""
|
|
53
|
+
return self._config.get("price_class", "PriceClass_100")
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def http_version(self) -> str:
|
|
57
|
+
"""HTTP version (http2, http2_and_3)"""
|
|
58
|
+
return self._config.get("http_version", "http2_and_3")
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def certificate(self) -> Optional[Dict[str, Any]]:
|
|
62
|
+
"""ACM certificate configuration"""
|
|
63
|
+
return self._config.get("certificate")
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def origins(self) -> List[Dict[str, Any]]:
|
|
67
|
+
"""Origin configurations"""
|
|
68
|
+
return self._config.get("origins", [])
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def default_cache_behavior(self) -> Dict[str, Any]:
|
|
72
|
+
"""Default cache behavior"""
|
|
73
|
+
return self._config.get("default_cache_behavior", {})
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def cache_behaviors(self) -> List[Dict[str, Any]]:
|
|
77
|
+
"""Additional cache behaviors"""
|
|
78
|
+
return self._config.get("cache_behaviors", [])
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def custom_error_responses(self) -> List[Dict[str, Any]]:
|
|
82
|
+
"""Custom error responses"""
|
|
83
|
+
return self._config.get("custom_error_responses", [])
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def logging(self) -> Optional[Dict[str, Any]]:
|
|
87
|
+
"""Logging configuration"""
|
|
88
|
+
return self._config.get("logging")
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def waf_web_acl_id(self) -> Optional[str]:
|
|
92
|
+
"""WAF Web ACL ID"""
|
|
93
|
+
return self._config.get("waf_web_acl_id")
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def default_root_object(self) -> str:
|
|
97
|
+
"""Default root object"""
|
|
98
|
+
return self._config.get("default_root_object", "index.html")
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def tags(self) -> Dict[str, str]:
|
|
102
|
+
"""Resource tags"""
|
|
103
|
+
return self._config.get("tags", {})
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def ssm_exports(self) -> Dict[str, str]:
|
|
107
|
+
"""SSM parameter exports"""
|
|
108
|
+
return self._config.get("ssm_exports", {})
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def ssm_imports(self) -> Dict[str, str]:
|
|
112
|
+
"""SSM parameter imports"""
|
|
113
|
+
return self._config.get("ssm_imports", {})
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def hosted_zone_id(self) -> str:
|
|
117
|
+
"""
|
|
118
|
+
Returns the hosted_zone_id for cloudfront
|
|
119
|
+
Use this when making dns changes when you want your custom domain
|
|
120
|
+
to be route through cloudfront.
|
|
121
|
+
|
|
122
|
+
As far as I know this Id is static and used for all of cloudfront
|
|
123
|
+
"""
|
|
124
|
+
return self._config.get("hosted_zone_id", "Z2FDTNDATAQYW2")
|
{cdk_factory-0.9.11 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/ecs_service.py
RENAMED
|
@@ -142,3 +142,15 @@ class EcsServiceConfig:
|
|
|
142
142
|
def is_maintenance_mode(self) -> bool:
|
|
143
143
|
"""Whether this is a maintenance mode deployment"""
|
|
144
144
|
return self.deployment_type == "maintenance"
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def volumes(self) -> List[Dict[str, Any]]:
|
|
148
|
+
"""
|
|
149
|
+
Volume definitions for the task.
|
|
150
|
+
Supports host volumes for EC2 launch type and EFS volumes.
|
|
151
|
+
Each volume should have:
|
|
152
|
+
- name: volume name
|
|
153
|
+
- host: {source_path: "/path/on/host"} for bind mounts
|
|
154
|
+
- efs: {...} for EFS volumes
|
|
155
|
+
"""
|
|
156
|
+
return self.task_definition.get("volumes", [])
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda@Edge Configuration for CDK-Factory
|
|
3
|
+
Geek Cafe, LLC
|
|
4
|
+
Maintainers: Eric Wilson
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
from typing import Dict, Optional
|
|
8
|
+
from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LambdaEdgeConfig(EnhancedBaseConfig):
|
|
12
|
+
"""
|
|
13
|
+
Configuration class for Lambda@Edge functions.
|
|
14
|
+
Lambda@Edge has specific constraints:
|
|
15
|
+
- Must be deployed in us-east-1
|
|
16
|
+
- Max timeout: 5 seconds for origin-request/response, 30s for viewer-request/response
|
|
17
|
+
- Max memory: 10GB (but typically use 128-512MB for edge functions)
|
|
18
|
+
- Must use versioned functions (not $LATEST)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, config: dict = None, deployment=None) -> None:
|
|
22
|
+
super().__init__(
|
|
23
|
+
config or {},
|
|
24
|
+
resource_type="lambda_edge",
|
|
25
|
+
resource_name=config.get("name", "lambda-edge") if config else "lambda-edge"
|
|
26
|
+
)
|
|
27
|
+
self._config = config or {}
|
|
28
|
+
self._deployment = deployment
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def name(self) -> str:
|
|
32
|
+
"""Function name"""
|
|
33
|
+
return self._config.get("name", "lambda-edge")
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def handler(self) -> str:
|
|
37
|
+
"""Handler function (e.g., 'handler.lambda_handler')"""
|
|
38
|
+
return self._config.get("handler", "handler.lambda_handler")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def runtime(self) -> str:
|
|
42
|
+
"""Lambda runtime (e.g., 'python3.11')"""
|
|
43
|
+
return self._config.get("runtime", "python3.11")
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def memory_size(self) -> int:
|
|
47
|
+
"""Memory size in MB (128-10240)"""
|
|
48
|
+
return int(self._config.get("memory_size", 128))
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def timeout(self) -> int:
|
|
52
|
+
"""Timeout in seconds (max 5 for origin-request)"""
|
|
53
|
+
timeout = int(self._config.get("timeout", 5))
|
|
54
|
+
if timeout > 5:
|
|
55
|
+
raise ValueError("Lambda@Edge origin-request timeout cannot exceed 5 seconds")
|
|
56
|
+
return timeout
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def code_path(self) -> str:
|
|
60
|
+
"""Path to Lambda function code directory"""
|
|
61
|
+
return self._config.get("code_path", "./lambdas/edge/ip_gate")
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def environment(self) -> Dict[str, str]:
|
|
65
|
+
"""Environment variables for the Lambda function"""
|
|
66
|
+
return self._config.get("environment", {})
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def description(self) -> str:
|
|
70
|
+
"""Function description"""
|
|
71
|
+
return self._config.get("description", "Lambda@Edge function")
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def event_type(self) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Lambda@Edge event type:
|
|
77
|
+
- viewer-request: Executes when CloudFront receives a request from viewer
|
|
78
|
+
- origin-request: Executes before CloudFront forwards request to origin
|
|
79
|
+
- origin-response: Executes after CloudFront receives response from origin
|
|
80
|
+
- viewer-response: Executes before CloudFront returns response to viewer
|
|
81
|
+
"""
|
|
82
|
+
return self._config.get("event_type", "origin-request")
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def publish_version(self) -> bool:
|
|
86
|
+
"""Whether to publish a new version (required for Lambda@Edge)"""
|
|
87
|
+
return self._config.get("publish_version", True)
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def include_body(self) -> bool:
|
|
91
|
+
"""Whether to include request body in origin-request events"""
|
|
92
|
+
return self._config.get("include_body", False)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Monitoring Configuration
|
|
3
|
+
Geek Cafe, LLC
|
|
4
|
+
Maintainers: Eric Wilson
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, List, Any, Optional
|
|
9
|
+
from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MonitoringConfig(EnhancedBaseConfig):
|
|
13
|
+
"""
|
|
14
|
+
Monitoring Configuration for CloudWatch Alarms and Dashboards
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: dict = None, deployment=None) -> None:
|
|
18
|
+
super().__init__(
|
|
19
|
+
config or {},
|
|
20
|
+
resource_type="monitoring",
|
|
21
|
+
resource_name=config.get("name", "monitoring") if config else "monitoring"
|
|
22
|
+
)
|
|
23
|
+
self._config = config or {}
|
|
24
|
+
self._deployment = deployment
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def name(self) -> str:
|
|
28
|
+
"""Monitoring stack name"""
|
|
29
|
+
return self._config.get("name", "monitoring")
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def sns_topics(self) -> List[Dict[str, Any]]:
|
|
33
|
+
"""SNS topics for alarm notifications"""
|
|
34
|
+
return self._config.get("sns_topics", [])
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def alarms(self) -> List[Dict[str, Any]]:
|
|
38
|
+
"""CloudWatch alarms configuration"""
|
|
39
|
+
return self._config.get("alarms", [])
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def dashboards(self) -> List[Dict[str, Any]]:
|
|
43
|
+
"""CloudWatch dashboards configuration"""
|
|
44
|
+
return self._config.get("dashboards", [])
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def composite_alarms(self) -> List[Dict[str, Any]]:
|
|
48
|
+
"""Composite alarms (combine multiple alarms)"""
|
|
49
|
+
return self._config.get("composite_alarms", [])
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def log_metric_filters(self) -> List[Dict[str, Any]]:
|
|
53
|
+
"""CloudWatch Logs metric filters"""
|
|
54
|
+
return self._config.get("log_metric_filters", [])
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def enable_anomaly_detection(self) -> bool:
|
|
58
|
+
"""Enable CloudWatch anomaly detection"""
|
|
59
|
+
return self._config.get("enable_anomaly_detection", False)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def tags(self) -> Dict[str, str]:
|
|
63
|
+
"""Resource tags"""
|
|
64
|
+
return self._config.get("tags", {})
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def ssm_exports(self) -> Dict[str, str]:
|
|
68
|
+
"""SSM parameter exports"""
|
|
69
|
+
return self._config.get("ssm_exports", {})
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def ssm_imports(self) -> Dict[str, str]:
|
|
73
|
+
"""SSM parameter imports for resource ARNs"""
|
|
74
|
+
return self._config.get("ssm_imports", {})
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from typing import Any, List, Mapping
|
|
1
|
+
from typing import Any, List, Mapping, Optional
|
|
2
2
|
|
|
3
3
|
from aws_cdk import Duration
|
|
4
4
|
from aws_cdk import aws_certificatemanager as acm
|
|
5
5
|
from aws_cdk import aws_cloudfront as cloudfront
|
|
6
6
|
from aws_cdk import aws_cloudfront_origins as origins
|
|
7
7
|
from aws_cdk import aws_iam as iam
|
|
8
|
+
from aws_cdk import aws_lambda as _lambda
|
|
8
9
|
from aws_cdk import aws_s3 as s3
|
|
9
10
|
from constructs import Construct
|
|
10
11
|
from cdk_factory.configurations.stack import StackConfig
|
|
@@ -123,6 +124,7 @@ class CloudFrontDistributionConstruct(Construct):
|
|
|
123
124
|
origin=origin,
|
|
124
125
|
viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
125
126
|
function_associations=self.__get_function_associations(),
|
|
127
|
+
edge_lambdas=self.__get_lambda_edge_associations(),
|
|
126
128
|
),
|
|
127
129
|
default_root_object="index.html",
|
|
128
130
|
error_responses=self._error_responses(),
|
|
@@ -218,6 +220,54 @@ class CloudFrontDistributionConstruct(Construct):
|
|
|
218
220
|
|
|
219
221
|
return function_associations
|
|
220
222
|
|
|
223
|
+
def __get_lambda_edge_associations(self) -> Optional[List[cloudfront.EdgeLambda]]:
|
|
224
|
+
"""
|
|
225
|
+
Get the Lambda@Edge associations for the distribution from config.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
List[cloudfront.EdgeLambda] or None: list of Lambda@Edge associations
|
|
229
|
+
"""
|
|
230
|
+
edge_lambdas = []
|
|
231
|
+
|
|
232
|
+
if self.stack_config and isinstance(self.stack_config, StackConfig):
|
|
233
|
+
cloudfront_config = self.stack_config.dictionary.get("cloudfront", {})
|
|
234
|
+
lambda_edge_associations = cloudfront_config.get("lambda_edge_associations", [])
|
|
235
|
+
|
|
236
|
+
for association in lambda_edge_associations:
|
|
237
|
+
event_type_str = association.get("event_type", "origin-request")
|
|
238
|
+
lambda_arn = association.get("lambda_arn")
|
|
239
|
+
include_body = association.get("include_body", False)
|
|
240
|
+
|
|
241
|
+
if not lambda_arn:
|
|
242
|
+
continue # Skip if no ARN provided
|
|
243
|
+
|
|
244
|
+
# Map event type string to CloudFront enum
|
|
245
|
+
event_type_map = {
|
|
246
|
+
"viewer-request": cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
|
|
247
|
+
"origin-request": cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
248
|
+
"origin-response": cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE,
|
|
249
|
+
"viewer-response": cloudfront.LambdaEdgeEventType.VIEWER_RESPONSE,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
event_type = event_type_map.get(event_type_str, cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST)
|
|
253
|
+
|
|
254
|
+
# Import the Lambda function version by ARN
|
|
255
|
+
lambda_version = _lambda.Version.from_version_arn(
|
|
256
|
+
self,
|
|
257
|
+
f"LambdaEdge-{event_type_str}",
|
|
258
|
+
version_arn=lambda_arn
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
edge_lambdas.append(
|
|
262
|
+
cloudfront.EdgeLambda(
|
|
263
|
+
function_version=lambda_version,
|
|
264
|
+
event_type=event_type,
|
|
265
|
+
include_body=include_body
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
return edge_lambdas if edge_lambdas else None
|
|
270
|
+
|
|
221
271
|
def __get_combined_function(self, hosts: List[str]) -> cloudfront.Function:
|
|
222
272
|
"""
|
|
223
273
|
Creates a combined CloudFront function that does both URL rewriting and host restrictions.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda@Edge Origin-Request Handler for IP-based Access Gating
|
|
3
|
+
Geek Cafe, LLC
|
|
4
|
+
Maintainers: Eric Wilson
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import ipaddress
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def lambda_handler(event, context):
|
|
13
|
+
"""
|
|
14
|
+
Lambda@Edge origin-request handler that implements IP-based gating
|
|
15
|
+
with maintenance site fallback.
|
|
16
|
+
|
|
17
|
+
Features:
|
|
18
|
+
- Inject X-Viewer-IP header for origin visibility
|
|
19
|
+
- Check viewer IP against allowlist when gate is enabled
|
|
20
|
+
- Rewrite blocked IPs to maintenance CloudFront distribution, and serve up maintenance site
|
|
21
|
+
- Toggle via GATE_ENABLED environment variable
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# Extract request from CloudFront event
|
|
25
|
+
request = event['Records'][0]['cf']['request']
|
|
26
|
+
client_ip = request['clientIp']
|
|
27
|
+
|
|
28
|
+
# Configuration from environment variables
|
|
29
|
+
gate_enabled = os.environ.get('GATE_ENABLED', 'false').lower() == 'true'
|
|
30
|
+
allow_cidrs_str = os.environ.get('ALLOW_CIDRS', '')
|
|
31
|
+
maint_cf_host = os.environ.get('MAINT_CF_HOST', '')
|
|
32
|
+
|
|
33
|
+
# Parse allowed CIDRs
|
|
34
|
+
allow_cidrs = [cidr.strip() for cidr in allow_cidrs_str.split(',') if cidr.strip()]
|
|
35
|
+
|
|
36
|
+
# Always inject viewer IP header
|
|
37
|
+
if 'headers' not in request:
|
|
38
|
+
request['headers'] = {}
|
|
39
|
+
|
|
40
|
+
request['headers']['x-viewer-ip'] = [{
|
|
41
|
+
'key': 'X-Viewer-IP',
|
|
42
|
+
'value': client_ip
|
|
43
|
+
}]
|
|
44
|
+
|
|
45
|
+
# If gate is disabled, pass through to origin
|
|
46
|
+
if not gate_enabled:
|
|
47
|
+
return request
|
|
48
|
+
|
|
49
|
+
# Check if IP is in allowlist
|
|
50
|
+
ip_allowed = False
|
|
51
|
+
try:
|
|
52
|
+
client_ip_obj = ipaddress.ip_address(client_ip)
|
|
53
|
+
for cidr in allow_cidrs:
|
|
54
|
+
try:
|
|
55
|
+
network = ipaddress.ip_network(cidr, strict=False)
|
|
56
|
+
if client_ip_obj in network:
|
|
57
|
+
ip_allowed = True
|
|
58
|
+
break
|
|
59
|
+
except (ValueError, ipaddress.AddressValueError):
|
|
60
|
+
# Invalid CIDR, skip
|
|
61
|
+
continue
|
|
62
|
+
except (ValueError, ipaddress.AddressValueError):
|
|
63
|
+
# Invalid client IP, block by default
|
|
64
|
+
ip_allowed = False
|
|
65
|
+
|
|
66
|
+
# If IP is allowed, pass through to origin
|
|
67
|
+
if ip_allowed:
|
|
68
|
+
return request
|
|
69
|
+
|
|
70
|
+
# IP not allowed - redirect to maintenance site
|
|
71
|
+
if not maint_cf_host:
|
|
72
|
+
# Safety: if maintenance host not configured, pass through with warning
|
|
73
|
+
# In production, you might want to return a fixed error response instead
|
|
74
|
+
return request
|
|
75
|
+
|
|
76
|
+
# Rewrite origin to maintenance CloudFront distribution
|
|
77
|
+
request['origin'] = {
|
|
78
|
+
'custom': {
|
|
79
|
+
'domainName': maint_cf_host,
|
|
80
|
+
'port': 443,
|
|
81
|
+
'protocol': 'https',
|
|
82
|
+
'path': '',
|
|
83
|
+
'sslProtocols': ['TLSv1.2'],
|
|
84
|
+
'readTimeout': 30,
|
|
85
|
+
'keepaliveTimeout': 5,
|
|
86
|
+
'customHeaders': {}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Update Host header to match new origin
|
|
91
|
+
request['headers']['host'] = [{
|
|
92
|
+
'key': 'Host',
|
|
93
|
+
'value': maint_cf_host
|
|
94
|
+
}]
|
|
95
|
+
|
|
96
|
+
# Normalize URI - redirect directory requests to index.html
|
|
97
|
+
uri = request.get('uri', '/')
|
|
98
|
+
if uri.endswith('/'):
|
|
99
|
+
request['uri'] = uri + 'index.html'
|
|
100
|
+
elif '.' not in uri.split('/')[-1]:
|
|
101
|
+
# No file extension, likely a directory
|
|
102
|
+
request['uri'] = uri + '/index.html'
|
|
103
|
+
|
|
104
|
+
return request
|
|
@@ -403,6 +403,7 @@ class PipelineFactoryStack(IStack):
|
|
|
403
403
|
relative_path = os.path.relpath(abs_output, abs_cwd)
|
|
404
404
|
return relative_path
|
|
405
405
|
except ValueError:
|
|
406
|
+
print(f"Failed to compute relative path from {abs_output} to {abs_cwd}")
|
|
406
407
|
# Different drives on Windows or other edge case
|
|
407
408
|
# Fall back to basename approach (just the directory name)
|
|
408
409
|
return "cdk.out"
|