cdk-factory 0.13.0__tar.gz → 0.13.2__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.
Files changed (158) hide show
  1. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/.gitignore +4 -1
  2. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/PKG-INFO +1 -1
  3. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/pyproject.toml +1 -1
  4. cdk_factory-0.13.2/src/cdk_factory/lambdas/edge/ip_gate/handler.py +187 -0
  5. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +48 -6
  6. cdk_factory-0.13.2/src/cdk_factory/version.py +1 -0
  7. cdk_factory-0.13.0/src/cdk_factory/lambdas/edge/ip_gate/handler.py +0 -104
  8. cdk_factory-0.13.0/src/cdk_factory/version.py +0 -1
  9. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/.windsurfrules +0 -0
  10. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/LICENSE +0 -0
  11. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/README.md +0 -0
  12. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/archive/README.md +0 -0
  13. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/archive/migrate_to_enhanced_ssm.py +0 -0
  14. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/examples/json-imports/README.md +0 -0
  15. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/examples/separate-api-gateway/README.md +0 -0
  16. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
  17. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/examples/separate-api-gateway/config.json +0 -0
  18. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/examples/separate-api-gateway/lambda-stack.json +0 -0
  19. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/mypy.ini +0 -0
  20. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/publish_to_pypi.py +0 -0
  21. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/publish_to_pypi.sh +0 -0
  22. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/pysetup.py +0 -0
  23. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/pysetup.sh +0 -0
  24. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/requirements.dev.txt +0 -0
  25. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/requirements.tests.txt +0 -0
  26. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/requirements.txt +0 -0
  27. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/run-checks.sh +0 -0
  28. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/run-tests-clean-venv.sh +0 -0
  29. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/run-tests.sh +0 -0
  30. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/__init__.py +0 -0
  31. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/app.py +0 -0
  32. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/builds/README.md +0 -0
  33. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/cdk.json +0 -0
  34. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/cli.py +0 -0
  35. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/commands/command_loader.py +0 -0
  36. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/base_config.py +0 -0
  37. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/cdk_config.py +0 -0
  38. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/deployment.py +0 -0
  39. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  40. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/devops.py +0 -0
  41. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  42. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  43. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/management.py +0 -0
  44. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/pipeline.py +0 -0
  45. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  46. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  47. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  48. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  49. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  50. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  51. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  52. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  53. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  54. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  55. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  56. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/docker.py +0 -0
  57. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  58. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  59. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/ecs_service.py +0 -0
  60. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  61. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/lambda_edge.py +0 -0
  62. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  63. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  64. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  65. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  66. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/monitoring.py +0 -0
  67. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/rds.py +0 -0
  68. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  69. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  70. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  71. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/route53.py +0 -0
  72. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  73. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/rum.py +0 -0
  74. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/s3.py +0 -0
  75. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  76. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  77. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  78. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  79. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/stack.py +0 -0
  80. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/configurations/workload.py +0 -0
  81. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +0 -0
  82. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  83. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  84. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  85. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  86. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  87. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  88. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  89. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  90. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  91. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  92. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
  93. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/interfaces/istack.py +0 -0
  94. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  95. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
  96. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/lambdas/health_handler.py +0 -0
  97. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/pipeline/path_utils.py +0 -0
  98. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
  99. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/pipeline/security/policies.py +0 -0
  100. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/pipeline/security/roles.py +0 -0
  101. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/pipeline/stage.py +0 -0
  102. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack/istack.py +0 -0
  103. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack/stack_factory.py +0 -0
  104. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  105. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  106. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack/stack_modules.py +0 -0
  107. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/__init__.py +0 -0
  108. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  109. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  110. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  111. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  112. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  113. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  114. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/cloudfront/__init__.py +0 -0
  115. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +0 -0
  116. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  117. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  118. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  119. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  120. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  121. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
  122. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +0 -0
  123. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/lambda_edge/__init__.py +0 -0
  124. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  125. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  126. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/monitoring/__init__.py +0 -0
  127. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +0 -0
  128. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  129. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  130. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  131. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
  132. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
  133. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
  134. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  135. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  136. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  137. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  138. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/stack_base.py +0 -0
  139. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  140. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  141. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  142. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  143. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/templates/README.md +0 -0
  144. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/templates/app.py.template +0 -0
  145. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/templates/cdk.json.template +0 -0
  146. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  147. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/commandline_args.py +0 -0
  148. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  149. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  150. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/environment_services.py +0 -0
  151. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/file_operations.py +0 -0
  152. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/git_utilities.py +0 -0
  153. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  154. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  155. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utilities/os_execute.py +0 -0
  156. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  157. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/cdk_factory/workload/workload_factory.py +0 -0
  158. {cdk_factory-0.13.0 → cdk_factory-0.13.2}/src/handlers/test/handler.py +0 -0
@@ -194,4 +194,7 @@ cdk.out
194
194
  .pysetup.json
195
195
  .delete
196
196
  activate.sh
197
- .lambda_package
197
+ .lambda_package
198
+
199
+ # Lambda runtime config (generated during CDK deployment)
200
+ **/runtime_config.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdk_factory
3
- Version: 0.13.0
3
+ Version: 0.13.2
4
4
  Summary: CDK Factory. A QuickStarter and best practices setup for CDK projects
5
5
  Author-email: Eric Wilson <eric.wilson@geekcafe.com>
6
6
  License: MIT License
@@ -33,7 +33,7 @@ markers = [
33
33
  [project]
34
34
 
35
35
  name = "cdk_factory"
36
- version = "0.13.0"
36
+ version = "0.13.2"
37
37
  authors = [
38
38
  { name="Eric Wilson", email="eric.wilson@geekcafe.com" }
39
39
  ]
@@ -0,0 +1,187 @@
1
+ """
2
+ Lambda@Edge function for IP-based access gating.
3
+ Geek Cafe, LLC
4
+ Maintainers: Eric Wilson
5
+
6
+ Since Lambda@Edge does not support environment variables, configuration
7
+ is fetched from SSM Parameter Store at runtime (with caching).
8
+ """
9
+ import json
10
+ import ipaddress
11
+ import boto3
12
+ from functools import lru_cache
13
+
14
+ # SSM client - will be created in the region where the function executes
15
+ ssm = None
16
+
17
+ @lru_cache(maxsize=128)
18
+ def get_ssm_parameter(parameter_name: str, region: str = 'us-east-1') -> str:
19
+ """
20
+ Fetch SSM parameter with caching.
21
+ Lambda@Edge cannot use environment variables, so we fetch from SSM.
22
+
23
+ Args:
24
+ parameter_name: Name of the SSM parameter
25
+ region: AWS region (default us-east-1)
26
+
27
+ Returns:
28
+ Parameter value
29
+ """
30
+ global ssm
31
+ if ssm is None:
32
+ ssm = boto3.client('ssm', region_name=region)
33
+
34
+ try:
35
+ response = ssm.get_parameter(Name=parameter_name, WithDecryption=False)
36
+ return response['Parameter']['Value']
37
+ except Exception as e:
38
+ print(f"Error fetching SSM parameter {parameter_name}: {str(e)}")
39
+ raise
40
+
41
+
42
+ def get_client_ip(request):
43
+ """Extract client IP from CloudFront request."""
44
+ if 'clientIp' in request:
45
+ return request['clientIp']
46
+
47
+ # Fallback to headers
48
+ headers = request.get('headers', {})
49
+ if 'x-forwarded-for' in headers:
50
+ xff = headers['x-forwarded-for'][0]['value']
51
+ return xff.split(',')[0].strip()
52
+
53
+ return None
54
+
55
+
56
+ def is_ip_allowed(client_ip: str, allowed_cidrs: list) -> bool:
57
+ """
58
+ Check if client IP is in any of the allowed CIDR ranges.
59
+
60
+ Args:
61
+ client_ip: Client IP address
62
+ allowed_cidrs: List of CIDR ranges (e.g., ['10.0.0.0/8', '192.168.1.0/24'])
63
+
64
+ Returns:
65
+ True if IP is allowed, False otherwise
66
+ """
67
+ if not client_ip:
68
+ return False
69
+
70
+ try:
71
+ client_ip_obj = ipaddress.ip_address(client_ip)
72
+ except ValueError as e:
73
+ print(f"Invalid client IP address: {e}")
74
+ return False
75
+
76
+ # Check each CIDR individually, skipping invalid ones
77
+ for cidr in allowed_cidrs:
78
+ try:
79
+ network = ipaddress.ip_network(cidr.strip(), strict=False)
80
+ if client_ip_obj in network:
81
+ return True
82
+ except ValueError as e:
83
+ # Invalid CIDR, log and continue checking others
84
+ print(f"Invalid CIDR '{cidr}': {e}")
85
+ continue
86
+
87
+ return False
88
+
89
+
90
+ def lambda_handler(event, context):
91
+ """
92
+ Lambda@Edge function for IP-based gating.
93
+
94
+ Configuration (fetched from SSM Parameter Store):
95
+ - GATE_ENABLED: Whether IP gating is enabled (true/false)
96
+ - ALLOW_CIDRS: Comma-separated list of allowed CIDR ranges
97
+ - MAINT_CF_HOST: CloudFront domain for maintenance/lockout page
98
+
99
+ Runtime configuration is bundled in runtime_config.json by CDK.
100
+ SSM parameter paths are auto-generated by CDK as:
101
+ /{environment}/{full-function-name}/{env-var-name-kebab-case}
102
+ """
103
+ request = event['Records'][0]['cf']['request']
104
+
105
+ # Load runtime configuration bundled by CDK
106
+ # This file is created during deployment and contains environment, function name, etc.
107
+ try:
108
+ with open('runtime_config.json', 'r') as f:
109
+ runtime_config = json.load(f)
110
+
111
+ env = runtime_config.get('environment', 'dev')
112
+ function_base_name = runtime_config.get('function_name', 'ip-gate')
113
+
114
+ print(f"Runtime config loaded: environment={env}, function_name={function_base_name}")
115
+ except FileNotFoundError:
116
+ # Fallback: extract from Lambda context (less reliable)
117
+ print("Warning: runtime_config.json not found, falling back to function name parsing")
118
+ function_full_name = context.function_name
119
+
120
+ # Parse environment from function name as fallback
121
+ parts = function_full_name.split('-')
122
+ common_envs = ['dev', 'prod', 'staging', 'test', 'qa', 'uat']
123
+ env = 'dev'
124
+
125
+ for part in parts:
126
+ if part in common_envs:
127
+ env = part
128
+ break
129
+
130
+ function_base_name = 'ip-gate'
131
+ print(f"Fallback: environment={env}, function_name={function_base_name}")
132
+
133
+ # Full function name for SSM paths
134
+ function_name = context.function_name
135
+ print(f"Lambda function ARN: {context.invoked_function_arn}")
136
+
137
+ try:
138
+ # Fetch configuration from SSM Parameter Store
139
+ # Auto-generated paths: /{env}/{function-name}/{key}
140
+ gate_enabled = get_ssm_parameter(f'/{env}/{function_name}/gate-enabled', 'us-east-1')
141
+
142
+ # If gating is disabled, allow all traffic
143
+ if gate_enabled.lower() not in ('true', '1', 'yes'):
144
+ print(f"IP gating is disabled (GATE_ENABLED={gate_enabled})")
145
+ return request
146
+
147
+ # Get allowed CIDRs and maintenance host
148
+ allow_cidrs_str = get_ssm_parameter(f'/{env}/{function_name}/allow-cidrs', 'us-east-1')
149
+ maint_cf_host = get_ssm_parameter(f'/{env}/{function_name}/maint-cf-host', 'us-east-1')
150
+
151
+ # Parse allowed CIDRs
152
+ allowed_cidrs = [cidr.strip() for cidr in allow_cidrs_str.split(',') if cidr.strip()]
153
+
154
+ # Get client IP
155
+ client_ip = get_client_ip(request)
156
+ print(f"Client IP: {client_ip}")
157
+
158
+ # Check if IP is allowed
159
+ if is_ip_allowed(client_ip, allowed_cidrs):
160
+ print(f"IP {client_ip} is allowed")
161
+ return request
162
+
163
+ # IP not allowed - redirect to maintenance page
164
+ print(f"IP {client_ip} is NOT allowed, redirecting to {maint_cf_host}")
165
+
166
+ response = {
167
+ 'status': '302',
168
+ 'statusDescription': 'Found',
169
+ 'headers': {
170
+ 'location': [{
171
+ 'key': 'Location',
172
+ 'value': f'https://{maint_cf_host}'
173
+ }],
174
+ 'cache-control': [{
175
+ 'key': 'Cache-Control',
176
+ 'value': 'no-cache, no-store, must-revalidate'
177
+ }]
178
+ }
179
+ }
180
+
181
+ return response
182
+
183
+ except Exception as e:
184
+ print(f"Error in IP gating function: {str(e)}")
185
+ # On error, allow the request to proceed (fail open)
186
+ # Change this to fail closed if preferred
187
+ return request
@@ -9,6 +9,9 @@ MIT License. See Project Root for the license information.
9
9
  from typing import Optional, Dict
10
10
  from pathlib import Path
11
11
  import json
12
+ import tempfile
13
+ import shutil
14
+ import importlib.resources
12
15
 
13
16
  import aws_cdk as cdk
14
17
  from aws_cdk import aws_lambda as _lambda
@@ -126,11 +129,38 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
126
129
  def _create_lambda_function(self, function_name: str) -> None:
127
130
  """Create the Lambda function"""
128
131
 
129
- # Resolve code path (relative to runtime directory or absolute)
130
- code_path = Path(self.edge_config.code_path)
131
- if not code_path.is_absolute():
132
- # Assume relative to the project root
133
- code_path = Path.cwd() / code_path
132
+ # Resolve code path - support package references (e.g., "cdk_factory:lambdas/edge/ip_gate")
133
+ code_path_str = self.edge_config.code_path
134
+
135
+ if ':' in code_path_str:
136
+ # Package reference format: "package_name:path/within/package"
137
+ package_name, package_path = code_path_str.split(':', 1)
138
+ logger.info(f"Resolving package reference: {package_name}:{package_path}")
139
+
140
+ try:
141
+ # Get the package's installed location
142
+ if hasattr(importlib.resources, 'files'):
143
+ # Python 3.9+
144
+ package_root = importlib.resources.files(package_name)
145
+ code_path = Path(str(package_root / package_path))
146
+ else:
147
+ # Fallback for older Python
148
+ import pkg_resources
149
+ package_root = pkg_resources.resource_filename(package_name, '')
150
+ code_path = Path(package_root) / package_path
151
+
152
+ logger.info(f"Resolved package path to: {code_path}")
153
+ except Exception as e:
154
+ raise FileNotFoundError(
155
+ f"Could not resolve package reference '{code_path_str}': {e}\n"
156
+ f"Make sure package '{package_name}' is installed."
157
+ )
158
+ else:
159
+ # Regular file path
160
+ code_path = Path(code_path_str)
161
+ if not code_path.is_absolute():
162
+ # Assume relative to the project root
163
+ code_path = Path.cwd() / code_path
134
164
 
135
165
  if not code_path.exists():
136
166
  raise FileNotFoundError(
@@ -140,6 +170,15 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
140
170
 
141
171
  logger.info(f"Loading Lambda code from: {code_path}")
142
172
 
173
+ # Create isolated temp directory for this function instance
174
+ # This prevents conflicts when multiple functions use the same handler code
175
+ temp_code_dir = Path(tempfile.mkdtemp(prefix=f"{function_name.replace('/', '-')}-"))
176
+ logger.info(f"Creating isolated code directory at: {temp_code_dir}")
177
+
178
+ # Copy source code to temp directory
179
+ shutil.copytree(code_path, temp_code_dir, dirs_exist_ok=True)
180
+ logger.info(f"Copied code from {code_path} to {temp_code_dir}")
181
+
143
182
  # Create runtime configuration file for Lambda@Edge
144
183
  # Since Lambda@Edge doesn't support environment variables, we bundle a config file
145
184
  runtime_config = {
@@ -148,7 +187,7 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
148
187
  'region': self.deployment.region
149
188
  }
150
189
 
151
- runtime_config_path = code_path / 'runtime_config.json'
190
+ runtime_config_path = temp_code_dir / 'runtime_config.json'
152
191
  logger.info(f"Creating runtime config at: {runtime_config_path}")
153
192
 
154
193
  with open(runtime_config_path, 'w') as f:
@@ -156,6 +195,9 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
156
195
 
157
196
  logger.info(f"Runtime config: {runtime_config}")
158
197
 
198
+ # Use the temp directory for the Lambda code asset
199
+ code_path = temp_code_dir
200
+
159
201
  # Map runtime string to CDK Runtime
160
202
  runtime_map = {
161
203
  "python3.11": _lambda.Runtime.PYTHON_3_11,
@@ -0,0 +1 @@
1
+ __version__ = "0.13.2"
@@ -1,104 +0,0 @@
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
@@ -1 +0,0 @@
1
- __version__ = "0.13.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes