cdk-factory 0.9.12__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.12 → cdk_factory-0.10.0}/PKG-INFO +1 -1
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/pyproject.toml +1 -1
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/run-tests.sh +10 -6
- {cdk_factory-0.9.12 → 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.12 → 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.12 → 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.12 → 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.12 → 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.12 → cdk_factory-0.10.0}/src/cdk_factory/workload/workload_factory.py +2 -0
- cdk_factory-0.9.12/src/cdk_factory/configurations/resources/cloudfront.py +0 -34
- cdk_factory-0.9.12/src/cdk_factory/version.py +0 -1
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/.gitignore +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/.windsurfrules +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/LICENSE +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/archive/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/archive/migrate_to_enhanced_ssm.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/examples/json-imports/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/examples/separate-api-gateway/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/examples/separate-api-gateway/config.json +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/examples/separate-api-gateway/lambda-stack.json +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/mypy.ini +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/publish_to_pypi.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/publish_to_pypi.sh +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/pysetup.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/pysetup.sh +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/requirements.dev.txt +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/requirements.tests.txt +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/requirements.txt +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/run-checks.sh +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/run-tests-clean-venv.sh +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/app.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/builds/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/cdk.json +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/cli.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/commands/command_loader.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/base_config.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/cdk_config.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/deployment.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/deployment_wave.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/devops.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/management.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/pipeline.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/_resources.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/cognito.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/docker.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/ecr.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/rds.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/route53.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/rum.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/s3.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/security_group.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/sqs.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/resources/vpc.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/configurations/workload.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/istack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/lambdas/health_handler.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/path_utils.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/security/policies.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/security/roles.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/pipeline/stage.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack/istack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_factory.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_module_loader.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_module_registry.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack/stack_modules.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/buckets/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecr/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/stack_base.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/templates/README.md +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/templates/app.py.template +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/templates/cdk.json.template +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/commandline_args.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/configuration_loader.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/docker_utilities.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/environment_services.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/file_operations.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/git_utilities.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utilities/os_execute.py +0 -0
- {cdk_factory-0.9.12 → cdk_factory-0.10.0}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
- {cdk_factory-0.9.12 → 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
|
{cdk_factory-0.9.12 → 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.12 → 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
|
|
@@ -193,6 +193,41 @@ class AutoScalingStack(IStack, EnhancedSsmParameterMixin):
|
|
|
193
193
|
iam.ManagedPolicy.from_aws_managed_policy_name(policy_name)
|
|
194
194
|
)
|
|
195
195
|
|
|
196
|
+
# Add inline policies (for custom permissions like S3 bucket access)
|
|
197
|
+
for policy_config in self.asg_config.iam_inline_policies:
|
|
198
|
+
policy_name = policy_config.get("name", "CustomPolicy")
|
|
199
|
+
statements = policy_config.get("statements", [])
|
|
200
|
+
|
|
201
|
+
if not statements:
|
|
202
|
+
logger.warning(f"No statements found for inline policy {policy_name}, skipping")
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
# Build policy statements
|
|
206
|
+
policy_statements = []
|
|
207
|
+
for stmt in statements:
|
|
208
|
+
effect = iam.Effect.ALLOW if stmt.get("effect", "Allow") == "Allow" else iam.Effect.DENY
|
|
209
|
+
actions = stmt.get("actions", [])
|
|
210
|
+
resources = stmt.get("resources", [])
|
|
211
|
+
|
|
212
|
+
if not actions or not resources:
|
|
213
|
+
logger.warning(f"Incomplete statement in policy {policy_name}, skipping")
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
policy_statements.append(
|
|
217
|
+
iam.PolicyStatement(
|
|
218
|
+
effect=effect,
|
|
219
|
+
actions=actions,
|
|
220
|
+
resources=resources
|
|
221
|
+
)
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
if policy_statements:
|
|
225
|
+
role.add_to_principal_policy(policy_statements[0])
|
|
226
|
+
for stmt in policy_statements[1:]:
|
|
227
|
+
role.add_to_principal_policy(stmt)
|
|
228
|
+
|
|
229
|
+
logger.info(f"Added inline policy {policy_name} with {len(policy_statements)} statements")
|
|
230
|
+
|
|
196
231
|
return role
|
|
197
232
|
|
|
198
233
|
def _create_user_data(self) -> ec2.UserData:
|
|
@@ -206,6 +241,10 @@ class AutoScalingStack(IStack, EnhancedSsmParameterMixin):
|
|
|
206
241
|
for command in self.asg_config.user_data_commands:
|
|
207
242
|
user_data.add_commands(command)
|
|
208
243
|
|
|
244
|
+
# Add user data scripts from files (with variable substitution)
|
|
245
|
+
if self.asg_config.user_data_scripts:
|
|
246
|
+
self._add_user_data_scripts_from_files(user_data)
|
|
247
|
+
|
|
209
248
|
# Add container configuration if specified
|
|
210
249
|
container_config = self.asg_config.container_config
|
|
211
250
|
if container_config:
|
|
@@ -213,6 +252,66 @@ class AutoScalingStack(IStack, EnhancedSsmParameterMixin):
|
|
|
213
252
|
|
|
214
253
|
return user_data
|
|
215
254
|
|
|
255
|
+
def _add_user_data_scripts_from_files(self, user_data: ec2.UserData) -> None:
|
|
256
|
+
"""
|
|
257
|
+
Add user data scripts from external files with variable substitution.
|
|
258
|
+
Supports loading shell scripts and injecting them into user data with
|
|
259
|
+
placeholder replacement.
|
|
260
|
+
"""
|
|
261
|
+
from pathlib import Path
|
|
262
|
+
|
|
263
|
+
for script_config in self.asg_config.user_data_scripts:
|
|
264
|
+
script_type = script_config.get("type", "file")
|
|
265
|
+
|
|
266
|
+
if script_type == "file":
|
|
267
|
+
# Load script from file
|
|
268
|
+
script_path = script_config.get("path")
|
|
269
|
+
if not script_path:
|
|
270
|
+
logger.warning("Script path not specified, skipping")
|
|
271
|
+
continue
|
|
272
|
+
|
|
273
|
+
# Resolve path (relative to project root or absolute)
|
|
274
|
+
path = Path(script_path)
|
|
275
|
+
if not path.is_absolute():
|
|
276
|
+
# Try relative to current working directory
|
|
277
|
+
path = Path.cwd() / script_path
|
|
278
|
+
|
|
279
|
+
if not path.exists():
|
|
280
|
+
logger.warning(f"Script file not found: {path}, skipping")
|
|
281
|
+
continue
|
|
282
|
+
|
|
283
|
+
# Read script content
|
|
284
|
+
try:
|
|
285
|
+
with open(path, 'r') as f:
|
|
286
|
+
script_content = f.read()
|
|
287
|
+
except Exception as e:
|
|
288
|
+
logger.error(f"Failed to read script file {path}: {e}")
|
|
289
|
+
continue
|
|
290
|
+
|
|
291
|
+
elif script_type == "inline":
|
|
292
|
+
# Use inline script content
|
|
293
|
+
script_content = script_config.get("content", "")
|
|
294
|
+
if not script_content:
|
|
295
|
+
logger.warning("Inline script content is empty, skipping")
|
|
296
|
+
continue
|
|
297
|
+
else:
|
|
298
|
+
logger.warning(f"Unknown script type: {script_type}, skipping")
|
|
299
|
+
continue
|
|
300
|
+
|
|
301
|
+
# Perform variable substitution
|
|
302
|
+
variables = script_config.get("variables", {})
|
|
303
|
+
for var_name, var_value in variables.items():
|
|
304
|
+
placeholder = f"{{{{{var_name}}}}}" # {{VAR_NAME}}
|
|
305
|
+
script_content = script_content.replace(placeholder, str(var_value))
|
|
306
|
+
|
|
307
|
+
# Add script to user data
|
|
308
|
+
# Split by lines and add each line as a command
|
|
309
|
+
for line in script_content.split('\n'):
|
|
310
|
+
if line.strip(): # Skip empty lines
|
|
311
|
+
user_data.add_commands(line)
|
|
312
|
+
|
|
313
|
+
logger.info(f"Added user data script from {script_type}: {script_config.get('path', 'inline')}")
|
|
314
|
+
|
|
216
315
|
def _add_container_user_data(
|
|
217
316
|
self, user_data: ec2.UserData, container_config: Dict[str, Any]
|
|
218
317
|
) -> None:
|