cdk-factory 0.12.0__tar.gz → 0.13.1__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.

Potentially problematic release.


This version of cdk-factory might be problematic. Click here for more details.

Files changed (158) hide show
  1. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/.gitignore +4 -1
  2. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/PKG-INFO +1 -1
  3. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/pyproject.toml +1 -1
  4. cdk_factory-0.13.1/src/cdk_factory/lambdas/edge/ip_gate/handler.py +187 -0
  5. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +92 -5
  6. cdk_factory-0.13.1/src/cdk_factory/version.py +1 -0
  7. cdk_factory-0.12.0/src/cdk_factory/lambdas/edge/ip_gate/handler.py +0 -104
  8. cdk_factory-0.12.0/src/cdk_factory/version.py +0 -1
  9. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/.windsurfrules +0 -0
  10. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/LICENSE +0 -0
  11. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/README.md +0 -0
  12. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/archive/README.md +0 -0
  13. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/archive/migrate_to_enhanced_ssm.py +0 -0
  14. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/examples/json-imports/README.md +0 -0
  15. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/examples/separate-api-gateway/README.md +0 -0
  16. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
  17. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/examples/separate-api-gateway/config.json +0 -0
  18. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/examples/separate-api-gateway/lambda-stack.json +0 -0
  19. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/mypy.ini +0 -0
  20. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/publish_to_pypi.py +0 -0
  21. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/publish_to_pypi.sh +0 -0
  22. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/pysetup.py +0 -0
  23. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/pysetup.sh +0 -0
  24. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/requirements.dev.txt +0 -0
  25. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/requirements.tests.txt +0 -0
  26. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/requirements.txt +0 -0
  27. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/run-checks.sh +0 -0
  28. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/run-tests-clean-venv.sh +0 -0
  29. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/run-tests.sh +0 -0
  30. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/__init__.py +0 -0
  31. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/app.py +0 -0
  32. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/builds/README.md +0 -0
  33. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/cdk.json +0 -0
  34. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/cli.py +0 -0
  35. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/commands/command_loader.py +0 -0
  36. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/base_config.py +0 -0
  37. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/cdk_config.py +0 -0
  38. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/deployment.py +0 -0
  39. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  40. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/devops.py +0 -0
  41. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  42. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  43. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/management.py +0 -0
  44. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/pipeline.py +0 -0
  45. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  46. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  47. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  48. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  49. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  50. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  51. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  52. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  53. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  54. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  55. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  56. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/docker.py +0 -0
  57. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  58. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  59. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/ecs_service.py +0 -0
  60. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  61. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/lambda_edge.py +0 -0
  62. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  63. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  64. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  65. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  66. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/monitoring.py +0 -0
  67. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/rds.py +0 -0
  68. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  69. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  70. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  71. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/route53.py +0 -0
  72. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  73. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/rum.py +0 -0
  74. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/s3.py +0 -0
  75. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  76. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  77. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  78. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  79. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/stack.py +0 -0
  80. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/configurations/workload.py +0 -0
  81. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +0 -0
  82. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  83. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  84. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  85. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  86. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  87. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  88. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  89. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  90. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  91. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  92. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
  93. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/interfaces/istack.py +0 -0
  94. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  95. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
  96. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/lambdas/health_handler.py +0 -0
  97. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/pipeline/path_utils.py +0 -0
  98. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
  99. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/pipeline/security/policies.py +0 -0
  100. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/pipeline/security/roles.py +0 -0
  101. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/pipeline/stage.py +0 -0
  102. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack/istack.py +0 -0
  103. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack/stack_factory.py +0 -0
  104. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  105. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  106. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack/stack_modules.py +0 -0
  107. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/__init__.py +0 -0
  108. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  109. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  110. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  111. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  112. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  113. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  114. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/cloudfront/__init__.py +0 -0
  115. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +0 -0
  116. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  117. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  118. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  119. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  120. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  121. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
  122. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +0 -0
  123. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/lambda_edge/__init__.py +0 -0
  124. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  125. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  126. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/monitoring/__init__.py +0 -0
  127. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +0 -0
  128. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  129. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  130. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  131. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
  132. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
  133. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
  134. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  135. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  136. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  137. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  138. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/stack_base.py +0 -0
  139. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  140. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  141. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  142. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  143. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/templates/README.md +0 -0
  144. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/templates/app.py.template +0 -0
  145. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/templates/cdk.json.template +0 -0
  146. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  147. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/commandline_args.py +0 -0
  148. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  149. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  150. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/environment_services.py +0 -0
  151. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/file_operations.py +0 -0
  152. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/git_utilities.py +0 -0
  153. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  154. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  155. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utilities/os_execute.py +0 -0
  156. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  157. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/src/cdk_factory/workload/workload_factory.py +0 -0
  158. {cdk_factory-0.12.0 → cdk_factory-0.13.1}/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.12.0
3
+ Version: 0.13.1
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.12.0"
36
+ version = "0.13.1"
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
@@ -8,6 +8,9 @@ MIT License. See Project Root for the license information.
8
8
 
9
9
  from typing import Optional, Dict
10
10
  from pathlib import Path
11
+ import json
12
+ import tempfile
13
+ import shutil
11
14
 
12
15
  import aws_cdk as cdk
13
16
  from aws_cdk import aws_lambda as _lambda
@@ -139,6 +142,34 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
139
142
 
140
143
  logger.info(f"Loading Lambda code from: {code_path}")
141
144
 
145
+ # Create isolated temp directory for this function instance
146
+ # This prevents conflicts when multiple functions use the same handler code
147
+ temp_code_dir = Path(tempfile.mkdtemp(prefix=f"{function_name.replace('/', '-')}-"))
148
+ logger.info(f"Creating isolated code directory at: {temp_code_dir}")
149
+
150
+ # Copy source code to temp directory
151
+ shutil.copytree(code_path, temp_code_dir, dirs_exist_ok=True)
152
+ logger.info(f"Copied code from {code_path} to {temp_code_dir}")
153
+
154
+ # Create runtime configuration file for Lambda@Edge
155
+ # Since Lambda@Edge doesn't support environment variables, we bundle a config file
156
+ runtime_config = {
157
+ 'environment': self.deployment.environment,
158
+ 'function_name': self.edge_config.name,
159
+ 'region': self.deployment.region
160
+ }
161
+
162
+ runtime_config_path = temp_code_dir / 'runtime_config.json'
163
+ logger.info(f"Creating runtime config at: {runtime_config_path}")
164
+
165
+ with open(runtime_config_path, 'w') as f:
166
+ json.dump(runtime_config, f, indent=2)
167
+
168
+ logger.info(f"Runtime config: {runtime_config}")
169
+
170
+ # Use the temp directory for the Lambda code asset
171
+ code_path = temp_code_dir
172
+
142
173
  # Map runtime string to CDK Runtime
143
174
  runtime_map = {
144
175
  "python3.11": _lambda.Runtime.PYTHON_3_11,
@@ -154,10 +185,23 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
154
185
  _lambda.Runtime.PYTHON_3_11
155
186
  )
156
187
 
157
- # Resolve environment variables (handles SSM parameter references)
158
- resolved_environment = self._resolve_environment_variables()
188
+ # Lambda@Edge does NOT support environment variables
189
+ # Configuration must be handled via:
190
+ # 1. Hardcoded in the function code
191
+ # 2. Fetched from SSM Parameter Store at runtime
192
+ # 3. Other configuration mechanisms
193
+
194
+ # Log warning if environment variables are configured
195
+ if self.edge_config.environment:
196
+ logger.warning(
197
+ f"Lambda@Edge function '{function_name}' has environment variables configured, "
198
+ "but Lambda@Edge does not support environment variables. "
199
+ "The function must fetch these values from SSM Parameter Store at runtime."
200
+ )
201
+ for key, value in self.edge_config.environment.items():
202
+ logger.warning(f" - {key}: {value}")
159
203
 
160
- # Create execution role with CloudWatch Logs permissions
204
+ # Create execution role with CloudWatch Logs and SSM permissions
161
205
  execution_role = iam.Role(
162
206
  self,
163
207
  f"{function_name}-Role",
@@ -173,7 +217,23 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
173
217
  ]
174
218
  )
175
219
 
176
- # Create the Lambda function
220
+ # Add SSM read permissions if environment variables reference SSM parameters
221
+ if self.edge_config.environment:
222
+ execution_role.add_to_policy(
223
+ iam.PolicyStatement(
224
+ effect=iam.Effect.ALLOW,
225
+ actions=[
226
+ "ssm:GetParameter",
227
+ "ssm:GetParameters",
228
+ "ssm:GetParametersByPath"
229
+ ],
230
+ resources=[
231
+ f"arn:aws:ssm:*:{cdk.Aws.ACCOUNT_ID}:parameter/*"
232
+ ]
233
+ )
234
+ )
235
+
236
+ # Create the Lambda function WITHOUT environment variables
177
237
  self.function = _lambda.Function(
178
238
  self,
179
239
  function_name,
@@ -185,7 +245,7 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
185
245
  timeout=cdk.Duration.seconds(self.edge_config.timeout),
186
246
  description=self.edge_config.description,
187
247
  role=execution_role,
188
- environment=resolved_environment,
248
+ # Lambda@Edge does NOT support environment variables
189
249
  log_retention=logs.RetentionDays.ONE_WEEK,
190
250
  )
191
251
 
@@ -256,3 +316,30 @@ class LambdaEdgeStack(IStack, EnhancedSsmParameterMixin):
256
316
  param_path,
257
317
  description=f"{key} for Lambda@Edge function {function_name}"
258
318
  )
319
+
320
+ # Export environment variables as SSM parameters
321
+ # Since Lambda@Edge doesn't support environment variables, we export them
322
+ # to SSM so the Lambda function can fetch them at runtime
323
+ if self.edge_config.environment:
324
+ logger.info("Exporting Lambda@Edge environment variables as SSM parameters")
325
+ env_ssm_exports = self.edge_config.dictionary.get("environment_ssm_exports", {})
326
+
327
+ # If no explicit environment_ssm_exports, create default SSM paths
328
+ if not env_ssm_exports:
329
+ # Auto-generate SSM parameter names based on environment variable names
330
+ for env_key in self.edge_config.environment.keys():
331
+ # Use snake_case version of the key for SSM path
332
+ ssm_key = env_key.lower().replace('_', '-')
333
+ env_ssm_exports[env_key] = f"/{self.deployment.environment}/{function_name}/{ssm_key}"
334
+
335
+ # Resolve and export environment variables to SSM
336
+ resolved_env = self._resolve_environment_variables()
337
+ for env_key, ssm_path in env_ssm_exports.items():
338
+ if env_key in resolved_env:
339
+ self.export_ssm_parameter(
340
+ self,
341
+ f"env-{env_key}-param",
342
+ resolved_env[env_key],
343
+ ssm_path,
344
+ description=f"Configuration for Lambda@Edge: {env_key}"
345
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.13.1"
@@ -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.12.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes