cdk-factory 0.7.26__py3-none-any.whl → 0.7.27__py3-none-any.whl
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/configurations/resources/apigateway_route_config.py +1 -1
- cdk_factory/stack_library/api_gateway/api_gateway_stack.py +39 -28
- cdk_factory/utilities/api_gateway_integration_utility.py +193 -139
- cdk_factory/version.py +1 -1
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.27.dist-info}/METADATA +1 -1
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.27.dist-info}/RECORD +8 -8
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.27.dist-info}/WHEEL +0 -0
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.27.dist-info}/licenses/LICENSE +0 -0
|
@@ -72,7 +72,7 @@ class ApiGatewayConfigRouteConfig:
|
|
|
72
72
|
@property
|
|
73
73
|
def allow_public_override(self) -> bool:
|
|
74
74
|
"""Whether to allow public access when Cognito is available"""
|
|
75
|
-
return self._config.get("allow_public_override", False)
|
|
75
|
+
return str(self._config.get("allow_public_override", False)).lower() == "true"
|
|
76
76
|
|
|
77
77
|
@property
|
|
78
78
|
def dictionary(self) -> Dict[str, Any]:
|
|
@@ -350,28 +350,30 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
350
350
|
def _validate_authorization_configuration(self, route, has_cognito_authorizer):
|
|
351
351
|
"""
|
|
352
352
|
Validate authorization configuration for security and clarity.
|
|
353
|
-
|
|
353
|
+
|
|
354
354
|
This method implements 'secure by default' with explicit overrides:
|
|
355
355
|
- If Cognito is available and route wants NONE auth, requires explicit override
|
|
356
356
|
- If Cognito is not available and route wants COGNITO auth, raises error
|
|
357
357
|
- Provides verbose warnings for monitoring and security awareness
|
|
358
|
-
|
|
358
|
+
|
|
359
359
|
Args:
|
|
360
360
|
route (dict): Route configuration
|
|
361
361
|
has_cognito_authorizer (bool): Whether a Cognito authorizer is configured
|
|
362
|
-
|
|
362
|
+
|
|
363
363
|
Raises:
|
|
364
364
|
ValueError: When there are security conflicts without explicit overrides
|
|
365
365
|
"""
|
|
366
366
|
import logging
|
|
367
|
-
|
|
368
|
-
auth_type = route.get("authorization_type", "COGNITO")
|
|
369
|
-
explicit_override =
|
|
367
|
+
|
|
368
|
+
auth_type = str(route.get("authorization_type", "COGNITO")).upper()
|
|
369
|
+
explicit_override = (
|
|
370
|
+
str(route.get("allow_public_override", False)).lower() == "true"
|
|
371
|
+
)
|
|
370
372
|
route_path = route.get("path", "unknown")
|
|
371
373
|
method = route.get("method", "unknown")
|
|
372
|
-
|
|
374
|
+
|
|
373
375
|
logger = logging.getLogger(__name__)
|
|
374
|
-
|
|
376
|
+
|
|
375
377
|
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
|
376
378
|
if has_cognito_authorizer and auth_type == "NONE" and not explicit_override:
|
|
377
379
|
error_msg = (
|
|
@@ -383,11 +385,12 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
383
385
|
f" 1. Remove Cognito configuration if you want public access\n"
|
|
384
386
|
f" 2. Add 'allow_public_override': true to explicitly allow public access\n"
|
|
385
387
|
f" 3. Remove 'authorization_type': 'NONE' to use secure Cognito auth\n\n"
|
|
386
|
-
f"🔒 This prevents accidental public endpoints when authentication is available
|
|
388
|
+
f"🔒 This prevents accidental public endpoints when authentication is available.\n\n"
|
|
389
|
+
f"👉 ApiGatewayStack documentation for more details: https://github.com/your-repo/api-gateway-stack"
|
|
387
390
|
)
|
|
388
391
|
raise ValueError(error_msg)
|
|
389
|
-
|
|
390
|
-
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
392
|
+
|
|
393
|
+
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
391
394
|
# Only error if COGNITO was explicitly requested, not if it's the default
|
|
392
395
|
if not has_cognito_authorizer and route.get("authorization_type") == "COGNITO":
|
|
393
396
|
error_msg = (
|
|
@@ -401,7 +404,7 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
401
404
|
f" 4. Remove explicit authorization_type to use default behavior"
|
|
402
405
|
)
|
|
403
406
|
raise ValueError(error_msg)
|
|
404
|
-
|
|
407
|
+
|
|
405
408
|
# Case 3: Cognito available + NONE requested + Explicit override = WARN
|
|
406
409
|
if has_cognito_authorizer and auth_type == "NONE" and explicit_override:
|
|
407
410
|
warning_msg = (
|
|
@@ -411,10 +414,10 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
411
414
|
f" 📊 Consider monitoring this endpoint for unexpected usage patterns\n"
|
|
412
415
|
f" 🔍 Review periodically: Should this endpoint be secured?"
|
|
413
416
|
)
|
|
414
|
-
|
|
417
|
+
|
|
415
418
|
# Print to console during deployment for visibility
|
|
416
419
|
print(warning_msg)
|
|
417
|
-
|
|
420
|
+
|
|
418
421
|
# Structured logging for monitoring and metrics
|
|
419
422
|
logger.warning(
|
|
420
423
|
"Public endpoint configured with Cognito available",
|
|
@@ -426,10 +429,10 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
426
429
|
"authorization_type": "NONE",
|
|
427
430
|
"metric_name": "public_endpoint_with_cognito",
|
|
428
431
|
"security_decision": "intentional_public",
|
|
429
|
-
"recommendation": "review_periodically"
|
|
430
|
-
}
|
|
432
|
+
"recommendation": "review_periodically",
|
|
433
|
+
},
|
|
431
434
|
)
|
|
432
|
-
|
|
435
|
+
|
|
433
436
|
# Case 4: No Cognito + NONE = INFO (expected for public-only APIs)
|
|
434
437
|
if not has_cognito_authorizer and auth_type == "NONE":
|
|
435
438
|
logger.info(
|
|
@@ -439,8 +442,8 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
439
442
|
"method": method,
|
|
440
443
|
"authorization_type": "NONE",
|
|
441
444
|
"cognito_available": False,
|
|
442
|
-
"security_decision": "public_only_api"
|
|
443
|
-
}
|
|
445
|
+
"security_decision": "public_only_api",
|
|
446
|
+
},
|
|
444
447
|
)
|
|
445
448
|
|
|
446
449
|
def _setup_lambda_integration(
|
|
@@ -448,23 +451,27 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
448
451
|
):
|
|
449
452
|
"""Setup Lambda integration for a route"""
|
|
450
453
|
import logging
|
|
451
|
-
|
|
454
|
+
|
|
452
455
|
route_path = route["path"]
|
|
453
456
|
# Secure by default: require Cognito authorization unless explicitly set to NONE
|
|
454
457
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
455
|
-
|
|
458
|
+
|
|
456
459
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
457
|
-
if
|
|
460
|
+
if (
|
|
461
|
+
not authorizer
|
|
462
|
+
and authorization_type == "COGNITO"
|
|
463
|
+
and "authorization_type" not in route
|
|
464
|
+
):
|
|
458
465
|
authorization_type = "NONE"
|
|
459
466
|
logger = logging.getLogger(__name__)
|
|
460
467
|
logger.info(
|
|
461
468
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
462
469
|
f"defaulting to public access (NONE authorization)"
|
|
463
470
|
)
|
|
464
|
-
|
|
471
|
+
|
|
465
472
|
# Validate authorization configuration for security
|
|
466
473
|
self._validate_authorization_configuration(route, authorizer is not None)
|
|
467
|
-
|
|
474
|
+
|
|
468
475
|
# If set to NONE (explicitly or by fallback), skip authorization
|
|
469
476
|
if authorization_type == "NONE":
|
|
470
477
|
authorizer = None
|
|
@@ -502,20 +509,24 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
502
509
|
):
|
|
503
510
|
"""Setup fallback Lambda integration for routes without src"""
|
|
504
511
|
import logging
|
|
505
|
-
|
|
512
|
+
|
|
506
513
|
route_path = route["path"]
|
|
507
514
|
# Secure by default: require Cognito authorization unless explicitly set to NONE
|
|
508
515
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
509
|
-
|
|
516
|
+
|
|
510
517
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
511
|
-
if
|
|
518
|
+
if (
|
|
519
|
+
not authorizer
|
|
520
|
+
and authorization_type == "COGNITO"
|
|
521
|
+
and "authorization_type" not in route
|
|
522
|
+
):
|
|
512
523
|
authorization_type = "NONE"
|
|
513
524
|
logger = logging.getLogger(__name__)
|
|
514
525
|
logger.info(
|
|
515
526
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
516
527
|
f"defaulting to public access (NONE authorization)"
|
|
517
528
|
)
|
|
518
|
-
|
|
529
|
+
|
|
519
530
|
# Validate authorization configuration for security
|
|
520
531
|
self._validate_authorization_configuration(route, authorizer is not None)
|
|
521
532
|
|
|
@@ -56,10 +56,13 @@ class ApiGatewayIntegrationUtility:
|
|
|
56
56
|
|
|
57
57
|
# Validate authorization configuration for security
|
|
58
58
|
has_cognito_authorizer = (
|
|
59
|
-
self.authorizer is not None
|
|
60
|
-
self._get_existing_authorizer_id_with_ssm_fallback(
|
|
59
|
+
self.authorizer is not None
|
|
60
|
+
or self._get_existing_authorizer_id_with_ssm_fallback(
|
|
61
|
+
api_config, stack_config
|
|
62
|
+
)
|
|
63
|
+
is not None
|
|
61
64
|
)
|
|
62
|
-
|
|
65
|
+
|
|
63
66
|
# Apply enhanced authorization validation and fallback logic
|
|
64
67
|
api_config = self._validate_and_adjust_authorization_configuration(
|
|
65
68
|
api_config, has_cognito_authorizer
|
|
@@ -79,7 +82,9 @@ class ApiGatewayIntegrationUtility:
|
|
|
79
82
|
)
|
|
80
83
|
|
|
81
84
|
# Add method to API Gateway
|
|
82
|
-
resource = self.get_or_create_resource(
|
|
85
|
+
resource = self.get_or_create_resource(
|
|
86
|
+
api_gateway, api_config.routes, stack_config
|
|
87
|
+
)
|
|
83
88
|
|
|
84
89
|
# Handle existing authorizer ID using L1 constructs
|
|
85
90
|
if self._get_existing_authorizer_id_with_ssm_fallback(api_config, stack_config):
|
|
@@ -101,7 +106,7 @@ class ApiGatewayIntegrationUtility:
|
|
|
101
106
|
# Use configured authorization type
|
|
102
107
|
auth_type = apigateway.AuthorizationType[api_config.authorization_type]
|
|
103
108
|
authorizer_to_use = None
|
|
104
|
-
|
|
109
|
+
|
|
105
110
|
method = None
|
|
106
111
|
try:
|
|
107
112
|
method = resource.add_method(
|
|
@@ -623,9 +628,11 @@ class ApiGatewayIntegrationUtility:
|
|
|
623
628
|
if stack_config:
|
|
624
629
|
api_gateway_config = stack_config.dictionary.get("api_gateway", {})
|
|
625
630
|
existing_resources = api_gateway_config.get("existing_resources", {})
|
|
626
|
-
|
|
631
|
+
|
|
627
632
|
if existing_resources:
|
|
628
|
-
return self._create_resource_with_imports(
|
|
633
|
+
return self._create_resource_with_imports(
|
|
634
|
+
api_gateway, route_path, existing_resources
|
|
635
|
+
)
|
|
629
636
|
|
|
630
637
|
# Use the built-in resource_for_path method which handles existing resources correctly
|
|
631
638
|
try:
|
|
@@ -682,27 +689,29 @@ class ApiGatewayIntegrationUtility:
|
|
|
682
689
|
) -> apigateway.Resource:
|
|
683
690
|
"""Create resource path using existing resource imports to avoid conflicts"""
|
|
684
691
|
from aws_cdk import aws_apigateway as apigateway
|
|
685
|
-
|
|
692
|
+
|
|
686
693
|
# Remove leading slash and split path
|
|
687
694
|
path_parts = route_path.lstrip("/").split("/")
|
|
688
695
|
current_resource = api_gateway.root
|
|
689
696
|
current_path = ""
|
|
690
|
-
|
|
697
|
+
|
|
691
698
|
# Navigate through path parts, importing existing resources where configured
|
|
692
699
|
for i, part in enumerate(path_parts):
|
|
693
700
|
if not part: # Skip empty parts
|
|
694
701
|
continue
|
|
695
|
-
|
|
696
|
-
current_path = "/" + "/".join(path_parts[:i+1])
|
|
697
|
-
|
|
702
|
+
|
|
703
|
+
current_path = "/" + "/".join(path_parts[: i + 1])
|
|
704
|
+
|
|
698
705
|
# Check if this path segment should be imported from existing resources
|
|
699
706
|
if current_path in existing_resources:
|
|
700
707
|
resource_config = existing_resources[current_path]
|
|
701
708
|
resource_id = resource_config.get("resource_id")
|
|
702
|
-
|
|
709
|
+
|
|
703
710
|
if resource_id:
|
|
704
|
-
logger.info(
|
|
705
|
-
|
|
711
|
+
logger.info(
|
|
712
|
+
f"Importing existing resource for path {current_path} with ID: {resource_id}"
|
|
713
|
+
)
|
|
714
|
+
|
|
706
715
|
# Import the existing resource using L1 constructs
|
|
707
716
|
current_resource = self._import_existing_resource(
|
|
708
717
|
api_gateway, current_resource, part, resource_id, current_path
|
|
@@ -713,33 +722,39 @@ class ApiGatewayIntegrationUtility:
|
|
|
713
722
|
else:
|
|
714
723
|
# Create normally for non-imported paths
|
|
715
724
|
current_resource = self._add_resource_safely(current_resource, part)
|
|
716
|
-
|
|
725
|
+
|
|
717
726
|
return current_resource
|
|
718
|
-
|
|
727
|
+
|
|
719
728
|
def _import_existing_resource(
|
|
720
|
-
self,
|
|
721
|
-
|
|
729
|
+
self,
|
|
730
|
+
api_gateway: apigateway.RestApi,
|
|
731
|
+
parent_resource: apigateway.Resource,
|
|
732
|
+
path_part: str,
|
|
733
|
+
resource_id: str,
|
|
734
|
+
full_path: str,
|
|
722
735
|
) -> apigateway.Resource:
|
|
723
736
|
"""Import an existing API Gateway resource by ID"""
|
|
724
737
|
from aws_cdk import aws_apigateway as apigateway
|
|
725
|
-
|
|
738
|
+
|
|
726
739
|
try:
|
|
727
740
|
# Use CfnResource to reference existing resource
|
|
728
741
|
# This creates a reference without trying to create the resource
|
|
729
742
|
imported_resource = apigateway.Resource.from_resource_id(
|
|
730
|
-
self.scope,
|
|
731
|
-
|
|
732
|
-
|
|
743
|
+
self.scope, f"imported-resource-{hash(full_path) % 10000}", resource_id
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
logger.info(
|
|
747
|
+
f"Successfully imported existing resource: {path_part} (ID: {resource_id})"
|
|
733
748
|
)
|
|
734
|
-
|
|
735
|
-
logger.info(f"Successfully imported existing resource: {path_part} (ID: {resource_id})")
|
|
736
749
|
return imported_resource
|
|
737
|
-
|
|
750
|
+
|
|
738
751
|
except Exception as e:
|
|
739
|
-
logger.warning(
|
|
752
|
+
logger.warning(
|
|
753
|
+
f"Failed to import resource {path_part} with ID {resource_id}: {e}"
|
|
754
|
+
)
|
|
740
755
|
# Fallback to normal creation
|
|
741
756
|
return self._add_resource_safely(parent_resource, path_part)
|
|
742
|
-
|
|
757
|
+
|
|
743
758
|
def _add_resource_safely(
|
|
744
759
|
self, parent_resource: apigateway.Resource, path_part: str
|
|
745
760
|
) -> apigateway.Resource:
|
|
@@ -747,9 +762,13 @@ class ApiGatewayIntegrationUtility:
|
|
|
747
762
|
try:
|
|
748
763
|
return parent_resource.add_resource(path_part)
|
|
749
764
|
except Exception as e:
|
|
750
|
-
if "AlreadyExists" in str(e) or "same parent already has this name" in str(
|
|
751
|
-
|
|
752
|
-
|
|
765
|
+
if "AlreadyExists" in str(e) or "same parent already has this name" in str(
|
|
766
|
+
e
|
|
767
|
+
):
|
|
768
|
+
logger.warning(
|
|
769
|
+
f"Resource {path_part} already exists, attempting to find existing resource"
|
|
770
|
+
)
|
|
771
|
+
|
|
753
772
|
# Try to find the existing resource in children
|
|
754
773
|
for child in parent_resource.node.children:
|
|
755
774
|
if (
|
|
@@ -758,7 +777,7 @@ class ApiGatewayIntegrationUtility:
|
|
|
758
777
|
):
|
|
759
778
|
logger.info(f"Found existing resource: {path_part}")
|
|
760
779
|
return child
|
|
761
|
-
|
|
780
|
+
|
|
762
781
|
# If not found in children, re-raise the error
|
|
763
782
|
logger.error(f"Could not find or create resource: {path_part}")
|
|
764
783
|
raise e
|
|
@@ -837,7 +856,7 @@ class ApiGatewayIntegrationUtility:
|
|
|
837
856
|
# Try enhanced SSM parameter lookup with auto-discovery
|
|
838
857
|
api_gateway_config = stack_config.dictionary.get("api_gateway", {})
|
|
839
858
|
ssm_config = api_gateway_config.get("ssm", {})
|
|
840
|
-
|
|
859
|
+
|
|
841
860
|
if ssm_config.get("enabled", False):
|
|
842
861
|
try:
|
|
843
862
|
from cdk_factory.interfaces.enhanced_ssm_parameter_mixin import (
|
|
@@ -859,26 +878,34 @@ class ApiGatewayIntegrationUtility:
|
|
|
859
878
|
imports_config = ssm_config.get("imports", {})
|
|
860
879
|
if "authorizer_id" in imports_config:
|
|
861
880
|
import_value = imports_config["authorizer_id"]
|
|
862
|
-
|
|
881
|
+
|
|
863
882
|
if import_value == "auto":
|
|
864
883
|
logger.info("Using auto-import for authorizer ID")
|
|
865
884
|
imported_values = ssm_mixin.auto_import_resources()
|
|
866
885
|
authorizer_id = imported_values.get("authorizer_id")
|
|
867
886
|
if authorizer_id:
|
|
868
|
-
logger.info(
|
|
887
|
+
logger.info(
|
|
888
|
+
f"Found authorizer ID via auto-import: {authorizer_id}"
|
|
889
|
+
)
|
|
869
890
|
return authorizer_id
|
|
870
891
|
else:
|
|
871
892
|
# Use direct parameter import for specific SSM path
|
|
872
|
-
logger.info(
|
|
893
|
+
logger.info(
|
|
894
|
+
f"Looking up authorizer ID from SSM parameter: {import_value}"
|
|
895
|
+
)
|
|
873
896
|
authorizer_id = ssm_mixin._import_enhanced_ssm_parameter(
|
|
874
897
|
import_value, "authorizer_id"
|
|
875
898
|
)
|
|
876
899
|
if authorizer_id:
|
|
877
|
-
logger.info(
|
|
900
|
+
logger.info(
|
|
901
|
+
f"Found authorizer ID from SSM: {authorizer_id}"
|
|
902
|
+
)
|
|
878
903
|
return authorizer_id
|
|
879
904
|
|
|
880
905
|
except Exception as e:
|
|
881
|
-
logger.warning(
|
|
906
|
+
logger.warning(
|
|
907
|
+
f"Failed to retrieve authorizer ID via enhanced SSM: {e}"
|
|
908
|
+
)
|
|
882
909
|
|
|
883
910
|
# Fallback to traditional SSM parameter lookup
|
|
884
911
|
authorizer_config = stack_config.dictionary.get("api_gateway", {}).get(
|
|
@@ -1041,7 +1068,9 @@ class ApiGatewayIntegrationUtility:
|
|
|
1041
1068
|
|
|
1042
1069
|
return exported_params
|
|
1043
1070
|
|
|
1044
|
-
def setup_route_cors(
|
|
1071
|
+
def setup_route_cors(
|
|
1072
|
+
self, resource: apigateway.Resource, route_path: str, route: dict
|
|
1073
|
+
):
|
|
1045
1074
|
"""Setup CORS for a route - centralized method for both API Gateway and Lambda stacks"""
|
|
1046
1075
|
cors_cfg = route.get("cors")
|
|
1047
1076
|
methods = cors_cfg.get("methods") if cors_cfg else None
|
|
@@ -1114,28 +1143,30 @@ class ApiGatewayIntegrationUtility:
|
|
|
1114
1143
|
stack_config: StackConfig,
|
|
1115
1144
|
api_config: Optional[ApiGatewayConfig] = None,
|
|
1116
1145
|
construct_scope: Optional[Construct] = None,
|
|
1117
|
-
counter: int = 1
|
|
1146
|
+
counter: int = 1,
|
|
1118
1147
|
) -> apigateway.Stage:
|
|
1119
1148
|
"""
|
|
1120
1149
|
Create deployment and stage for API Gateway with all integrations.
|
|
1121
1150
|
Consolidates logic from both API Gateway and Lambda stacks.
|
|
1122
1151
|
"""
|
|
1123
1152
|
scope = construct_scope or self.scope
|
|
1124
|
-
|
|
1153
|
+
|
|
1125
1154
|
# Determine stage name with fallback logic
|
|
1126
1155
|
stage_name = self._get_stage_name(stack_config, api_config)
|
|
1127
|
-
|
|
1156
|
+
|
|
1128
1157
|
# Check if using existing stage
|
|
1129
1158
|
use_existing = self._should_use_existing_stage(stack_config)
|
|
1130
|
-
|
|
1131
|
-
logger.info(
|
|
1132
|
-
|
|
1159
|
+
|
|
1160
|
+
logger.info(
|
|
1161
|
+
f"Creating deployment for API Gateway with {len(integrations)} integrations"
|
|
1162
|
+
)
|
|
1163
|
+
|
|
1133
1164
|
# Create deployment
|
|
1134
1165
|
deployment_id = f"api-gateway-{counter}-deployment-final"
|
|
1135
1166
|
if len(integrations) == 1 and integrations[0].get("function_name"):
|
|
1136
1167
|
# Lambda stack deployment
|
|
1137
1168
|
deployment_id = "api-gateway-deployment"
|
|
1138
|
-
|
|
1169
|
+
|
|
1139
1170
|
deployment = apigateway.Deployment(
|
|
1140
1171
|
scope,
|
|
1141
1172
|
deployment_id,
|
|
@@ -1145,83 +1176,95 @@ class ApiGatewayIntegrationUtility:
|
|
|
1145
1176
|
)
|
|
1146
1177
|
# Add timestamp to deployment logical ID to prevent conflicts and force new deployment
|
|
1147
1178
|
deployment.add_to_logical_id(datetime.now(UTC).isoformat())
|
|
1148
|
-
|
|
1179
|
+
|
|
1149
1180
|
# Create stage if not using existing
|
|
1150
1181
|
stage = None
|
|
1151
1182
|
if not use_existing:
|
|
1152
|
-
stage_options =
|
|
1183
|
+
stage_options = (
|
|
1184
|
+
self._create_stage_options(api_config) if api_config else None
|
|
1185
|
+
)
|
|
1153
1186
|
stage_id = f"{api_gateway.rest_api_name}-{stage_name}-stage"
|
|
1154
1187
|
if len(integrations) == 1 and integrations[0].get("function_name"):
|
|
1155
1188
|
# Lambda stack stage
|
|
1156
1189
|
stage_id = f"{api_gateway.rest_api_name}-{stage_name}-stage-lambdas"
|
|
1157
|
-
|
|
1190
|
+
|
|
1158
1191
|
stage_kwargs = {
|
|
1159
1192
|
"deployment": deployment,
|
|
1160
1193
|
"stage_name": stage_name,
|
|
1161
|
-
"description": f"Stage {stage_name} with {len(integrations)} integrations"
|
|
1194
|
+
"description": f"Stage {stage_name} with {len(integrations)} integrations",
|
|
1162
1195
|
}
|
|
1163
|
-
|
|
1196
|
+
|
|
1164
1197
|
# Add stage options if available
|
|
1165
1198
|
if stage_options:
|
|
1166
|
-
stage_kwargs.update(
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1199
|
+
stage_kwargs.update(
|
|
1200
|
+
{
|
|
1201
|
+
"access_log_destination": stage_options.access_log_destination,
|
|
1202
|
+
"access_log_format": stage_options.access_log_format,
|
|
1203
|
+
"logging_level": stage_options.logging_level,
|
|
1204
|
+
"data_trace_enabled": stage_options.data_trace_enabled,
|
|
1205
|
+
"metrics_enabled": stage_options.metrics_enabled,
|
|
1206
|
+
"tracing_enabled": stage_options.tracing_enabled,
|
|
1207
|
+
"throttling_rate_limit": stage_options.throttling_rate_limit,
|
|
1208
|
+
"throttling_burst_limit": stage_options.throttling_burst_limit,
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
|
|
1177
1212
|
stage = apigateway.Stage(scope, stage_id, **stage_kwargs)
|
|
1178
|
-
|
|
1179
|
-
logger.info(
|
|
1180
|
-
|
|
1181
|
-
|
|
1213
|
+
|
|
1214
|
+
logger.info(
|
|
1215
|
+
f"Created deployment and stage '{stage_name}' for API Gateway: {api_gateway.rest_api_name}"
|
|
1216
|
+
)
|
|
1217
|
+
logger.info(
|
|
1218
|
+
f"Routes available at: https://{api_gateway.rest_api_id}.execute-api.{scope.region}.amazonaws.com/{stage_name}"
|
|
1219
|
+
)
|
|
1220
|
+
|
|
1182
1221
|
return stage
|
|
1183
|
-
|
|
1184
|
-
def _get_stage_name(
|
|
1222
|
+
|
|
1223
|
+
def _get_stage_name(
|
|
1224
|
+
self, stack_config: StackConfig, api_config: Optional[ApiGatewayConfig] = None
|
|
1225
|
+
) -> str:
|
|
1185
1226
|
"""Get stage name with fallback logic from both stacks"""
|
|
1186
1227
|
# Try Lambda stack config format first
|
|
1187
1228
|
api_gateway_config = stack_config.dictionary.get("api_gateway", {})
|
|
1188
1229
|
stage_name = api_gateway_config.get("stage", {}).get("name")
|
|
1189
|
-
|
|
1230
|
+
|
|
1190
1231
|
if stage_name:
|
|
1191
1232
|
return stage_name
|
|
1192
|
-
|
|
1233
|
+
|
|
1193
1234
|
# Try API Gateway stack config format
|
|
1194
|
-
if api_config and hasattr(api_config,
|
|
1235
|
+
if api_config and hasattr(api_config, "stage_name") and api_config.stage_name:
|
|
1195
1236
|
stage_name = api_config.stage_name
|
|
1196
1237
|
else:
|
|
1197
1238
|
# Fallback to legacy format
|
|
1198
1239
|
stage_name = api_gateway_config.get("stage_name", "prod")
|
|
1199
|
-
|
|
1240
|
+
|
|
1200
1241
|
# Handle special cases
|
|
1201
1242
|
if stage_name is None:
|
|
1202
1243
|
raise ValueError("Stage name is required in API Gateway config")
|
|
1203
|
-
|
|
1244
|
+
|
|
1204
1245
|
if stage_name.lower() == "auto":
|
|
1205
1246
|
try:
|
|
1206
1247
|
stage_name = stack_config.name
|
|
1207
1248
|
except Exception as e:
|
|
1208
1249
|
raise ValueError("Stage name is required in API Gateway config") from e
|
|
1209
|
-
|
|
1250
|
+
|
|
1210
1251
|
return stage_name
|
|
1211
|
-
|
|
1252
|
+
|
|
1212
1253
|
def _should_use_existing_stage(self, stack_config: StackConfig) -> bool:
|
|
1213
1254
|
"""Check if should use existing stage"""
|
|
1214
1255
|
api_gateway_config = stack_config.dictionary.get("api_gateway", {})
|
|
1215
1256
|
use_existing = api_gateway_config.get("stage", {}).get("use_existing", False)
|
|
1216
1257
|
return str(use_existing).lower() == "true"
|
|
1217
|
-
|
|
1218
|
-
def _create_stage_options(
|
|
1258
|
+
|
|
1259
|
+
def _create_stage_options(
|
|
1260
|
+
self, api_config: ApiGatewayConfig
|
|
1261
|
+
) -> apigateway.StageOptions:
|
|
1219
1262
|
"""Create stage options with full configuration"""
|
|
1220
1263
|
log_group = self._setup_log_group()
|
|
1221
1264
|
access_log_format = self._get_log_format()
|
|
1222
|
-
|
|
1265
|
+
|
|
1223
1266
|
deploy_options = api_config.deploy_options or {}
|
|
1224
|
-
|
|
1267
|
+
|
|
1225
1268
|
return apigateway.StageOptions(
|
|
1226
1269
|
access_log_destination=apigateway.LogGroupLogDestination(log_group),
|
|
1227
1270
|
access_log_format=access_log_format,
|
|
@@ -1230,32 +1273,32 @@ class ApiGatewayIntegrationUtility:
|
|
|
1230
1273
|
metrics_enabled=deploy_options.get("metrics_enabled", False),
|
|
1231
1274
|
tracing_enabled=deploy_options.get("tracing_enabled", True),
|
|
1232
1275
|
throttling_rate_limit=deploy_options.get("throttling_rate_limit", 1000),
|
|
1233
|
-
throttling_burst_limit=deploy_options.get("throttling_burst_limit", 2000)
|
|
1276
|
+
throttling_burst_limit=deploy_options.get("throttling_burst_limit", 2000),
|
|
1234
1277
|
)
|
|
1235
|
-
|
|
1278
|
+
|
|
1236
1279
|
def _setup_log_group(self) -> logs.LogGroup:
|
|
1237
1280
|
"""Setup CloudWatch log group for API Gateway"""
|
|
1238
1281
|
if self._log_group:
|
|
1239
1282
|
return self._log_group
|
|
1240
|
-
|
|
1283
|
+
|
|
1241
1284
|
self._log_group = logs.LogGroup(
|
|
1242
1285
|
self.scope,
|
|
1243
1286
|
"ApiGatewayLogGroup",
|
|
1244
1287
|
removal_policy=RemovalPolicy.DESTROY,
|
|
1245
1288
|
retention=logs.RetentionDays.ONE_MONTH,
|
|
1246
1289
|
)
|
|
1247
|
-
|
|
1290
|
+
|
|
1248
1291
|
self._log_group.grant_write(iam.ServicePrincipal("apigateway.amazonaws.com"))
|
|
1249
1292
|
log_role = self._setup_log_role()
|
|
1250
1293
|
self._log_group.grant_write(log_role)
|
|
1251
|
-
|
|
1294
|
+
|
|
1252
1295
|
return self._log_group
|
|
1253
|
-
|
|
1296
|
+
|
|
1254
1297
|
def _setup_log_role(self) -> iam.Role:
|
|
1255
1298
|
"""Setup IAM role for API Gateway logging"""
|
|
1256
1299
|
if self._log_role:
|
|
1257
1300
|
return self._log_role
|
|
1258
|
-
|
|
1301
|
+
|
|
1259
1302
|
self._log_role = iam.Role(
|
|
1260
1303
|
self.scope,
|
|
1261
1304
|
"ApiGatewayLogRole",
|
|
@@ -1266,44 +1309,48 @@ class ApiGatewayIntegrationUtility:
|
|
|
1266
1309
|
)
|
|
1267
1310
|
],
|
|
1268
1311
|
)
|
|
1269
|
-
|
|
1312
|
+
|
|
1270
1313
|
return self._log_role
|
|
1271
|
-
|
|
1314
|
+
|
|
1272
1315
|
def _get_log_format(self) -> apigateway.AccessLogFormat:
|
|
1273
1316
|
"""Get access log format for API Gateway"""
|
|
1274
1317
|
return apigateway.AccessLogFormat.custom(
|
|
1275
|
-
json.dumps(
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1318
|
+
json.dumps(
|
|
1319
|
+
{
|
|
1320
|
+
"requestId": "$context.requestId",
|
|
1321
|
+
"extendedRequestId": "$context.extendedRequestId",
|
|
1322
|
+
"method": "$context.httpMethod",
|
|
1323
|
+
"route": "$context.resourcePath",
|
|
1324
|
+
"status": "$context.status",
|
|
1325
|
+
"requestBody": "$input.body",
|
|
1326
|
+
"responseBody": "$context.responseLength",
|
|
1327
|
+
"headers": "$context.requestHeaders",
|
|
1328
|
+
"requestContext": "$context.requestContext",
|
|
1329
|
+
}
|
|
1330
|
+
)
|
|
1286
1331
|
)
|
|
1287
|
-
|
|
1288
|
-
def group_integrations_by_api_gateway(
|
|
1332
|
+
|
|
1333
|
+
def group_integrations_by_api_gateway(
|
|
1334
|
+
self, integrations: List[Dict[str, Any]]
|
|
1335
|
+
) -> Dict[int, Dict[str, Any]]:
|
|
1289
1336
|
"""Group integrations by API Gateway using object identity"""
|
|
1290
1337
|
api_gateways = {}
|
|
1291
1338
|
api_counter = 0
|
|
1292
|
-
|
|
1339
|
+
|
|
1293
1340
|
for integration in integrations:
|
|
1294
|
-
api_gateway = integration.get(
|
|
1341
|
+
api_gateway = integration.get("api_gateway")
|
|
1295
1342
|
if api_gateway:
|
|
1296
1343
|
# Use object identity as key instead of CDK token
|
|
1297
1344
|
api_key = id(api_gateway)
|
|
1298
1345
|
if api_key not in api_gateways:
|
|
1299
1346
|
api_counter += 1
|
|
1300
1347
|
api_gateways[api_key] = {
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1348
|
+
"api_gateway": api_gateway,
|
|
1349
|
+
"integrations": [],
|
|
1350
|
+
"counter": api_counter,
|
|
1304
1351
|
}
|
|
1305
|
-
api_gateways[api_key][
|
|
1306
|
-
|
|
1352
|
+
api_gateways[api_key]["integrations"].append(integration)
|
|
1353
|
+
|
|
1307
1354
|
return api_gateways
|
|
1308
1355
|
|
|
1309
1356
|
def _validate_and_adjust_authorization_configuration(
|
|
@@ -1311,39 +1358,41 @@ class ApiGatewayIntegrationUtility:
|
|
|
1311
1358
|
) -> ApiGatewayConfigRouteConfig:
|
|
1312
1359
|
"""
|
|
1313
1360
|
Validate and adjust authorization configuration for security and clarity.
|
|
1314
|
-
|
|
1361
|
+
|
|
1315
1362
|
This method implements 'secure by default' with explicit overrides:
|
|
1316
1363
|
- If Cognito is available and route wants NONE auth, requires explicit override
|
|
1317
1364
|
- If Cognito is not available and route wants COGNITO auth, raises error
|
|
1318
1365
|
- Provides verbose warnings for monitoring and security awareness
|
|
1319
1366
|
- Returns a potentially modified api_config with adjusted authorization_type
|
|
1320
|
-
|
|
1367
|
+
|
|
1321
1368
|
Args:
|
|
1322
1369
|
api_config (ApiGatewayConfigRouteConfig): Route configuration
|
|
1323
1370
|
has_cognito_authorizer (bool): Whether a Cognito authorizer is configured
|
|
1324
|
-
|
|
1371
|
+
|
|
1325
1372
|
Returns:
|
|
1326
1373
|
ApiGatewayConfigRouteConfig: Potentially modified configuration
|
|
1327
|
-
|
|
1374
|
+
|
|
1328
1375
|
Raises:
|
|
1329
1376
|
ValueError: When there are security conflicts without explicit overrides
|
|
1330
1377
|
"""
|
|
1331
1378
|
import logging
|
|
1332
1379
|
from copy import deepcopy
|
|
1333
|
-
|
|
1380
|
+
|
|
1334
1381
|
# Create a copy to avoid modifying the original
|
|
1335
1382
|
modified_config = deepcopy(api_config)
|
|
1336
|
-
|
|
1337
|
-
auth_type = getattr(api_config,
|
|
1338
|
-
|
|
1383
|
+
|
|
1384
|
+
auth_type = str(getattr(api_config, "authorization_type", "COGNITO")).upper()
|
|
1385
|
+
|
|
1339
1386
|
# Check for explicit override flag
|
|
1340
|
-
explicit_override =
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1387
|
+
explicit_override = (
|
|
1388
|
+
str(getattr(api_config, "allow_public_override", False)).lower() == "true"
|
|
1389
|
+
)
|
|
1390
|
+
|
|
1391
|
+
route_path = getattr(api_config, "routes", "unknown")
|
|
1392
|
+
method = getattr(api_config, "method", "unknown")
|
|
1393
|
+
|
|
1345
1394
|
logger = logging.getLogger(__name__)
|
|
1346
|
-
|
|
1395
|
+
|
|
1347
1396
|
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
|
1348
1397
|
if has_cognito_authorizer and auth_type == "NONE" and not explicit_override:
|
|
1349
1398
|
error_msg = (
|
|
@@ -1355,16 +1404,17 @@ class ApiGatewayIntegrationUtility:
|
|
|
1355
1404
|
f" 1. Remove Cognito configuration if you want public access\n"
|
|
1356
1405
|
f" 2. Add 'allow_public_override': true to explicitly allow public access\n"
|
|
1357
1406
|
f" 3. Remove 'authorization_type': 'NONE' to use secure Cognito auth\n\n"
|
|
1358
|
-
f"🔒 This prevents accidental public endpoints when authentication is available
|
|
1407
|
+
f"🔒 This prevents accidental public endpoints when authentication is available.\n\n"
|
|
1408
|
+
f"👉 ApiGatewayIntegrationUtility documentation for more details: https://github.com/your-repo/api-gateway-stack"
|
|
1359
1409
|
)
|
|
1360
1410
|
raise ValueError(error_msg)
|
|
1361
|
-
|
|
1362
|
-
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
1411
|
+
|
|
1412
|
+
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
1363
1413
|
# Only error if COGNITO was explicitly requested, not if it's the default
|
|
1364
1414
|
original_auth_type = None
|
|
1365
|
-
if hasattr(api_config,
|
|
1366
|
-
original_auth_type = api_config.dictionary.get(
|
|
1367
|
-
|
|
1415
|
+
if hasattr(api_config, "dictionary") and api_config.dictionary:
|
|
1416
|
+
original_auth_type = api_config.dictionary.get("authorization_type")
|
|
1417
|
+
|
|
1368
1418
|
if not has_cognito_authorizer and original_auth_type == "COGNITO":
|
|
1369
1419
|
error_msg = (
|
|
1370
1420
|
f"🚨 CONFIGURATION ERROR for route {route_path} ({method}):\n"
|
|
@@ -1377,7 +1427,7 @@ class ApiGatewayIntegrationUtility:
|
|
|
1377
1427
|
f" 4. Remove explicit authorization_type to use default behavior"
|
|
1378
1428
|
)
|
|
1379
1429
|
raise ValueError(error_msg)
|
|
1380
|
-
|
|
1430
|
+
|
|
1381
1431
|
# Case 3: Cognito available + NONE requested + Explicit override = WARN
|
|
1382
1432
|
if has_cognito_authorizer and auth_type == "NONE" and explicit_override:
|
|
1383
1433
|
warning_msg = (
|
|
@@ -1387,10 +1437,10 @@ class ApiGatewayIntegrationUtility:
|
|
|
1387
1437
|
f" 📊 Consider monitoring this endpoint for unexpected usage patterns\n"
|
|
1388
1438
|
f" 🔍 Review periodically: Should this endpoint be secured?"
|
|
1389
1439
|
)
|
|
1390
|
-
|
|
1440
|
+
|
|
1391
1441
|
# Print to console during deployment for visibility
|
|
1392
1442
|
print(warning_msg)
|
|
1393
|
-
|
|
1443
|
+
|
|
1394
1444
|
# Structured logging for monitoring and metrics
|
|
1395
1445
|
logger.warning(
|
|
1396
1446
|
"Public endpoint configured with Cognito available",
|
|
@@ -1402,18 +1452,22 @@ class ApiGatewayIntegrationUtility:
|
|
|
1402
1452
|
"authorization_type": "NONE",
|
|
1403
1453
|
"metric_name": "public_endpoint_with_cognito",
|
|
1404
1454
|
"security_decision": "intentional_public",
|
|
1405
|
-
"recommendation": "review_periodically"
|
|
1406
|
-
}
|
|
1455
|
+
"recommendation": "review_periodically",
|
|
1456
|
+
},
|
|
1407
1457
|
)
|
|
1408
|
-
|
|
1458
|
+
|
|
1409
1459
|
# Case 4: No Cognito + default COGNITO = Fall back to NONE
|
|
1410
|
-
if
|
|
1460
|
+
if (
|
|
1461
|
+
not has_cognito_authorizer
|
|
1462
|
+
and auth_type == "COGNITO"
|
|
1463
|
+
and original_auth_type is None
|
|
1464
|
+
):
|
|
1411
1465
|
modified_config.authorization_type = "NONE"
|
|
1412
1466
|
logger.info(
|
|
1413
1467
|
f"No Cognito authorizer available for route {route_path} ({method}), "
|
|
1414
1468
|
f"defaulting to public access (NONE authorization)"
|
|
1415
1469
|
)
|
|
1416
|
-
|
|
1470
|
+
|
|
1417
1471
|
# Case 5: No Cognito + NONE = INFO (expected for public-only APIs)
|
|
1418
1472
|
if not has_cognito_authorizer and auth_type == "NONE":
|
|
1419
1473
|
logger.info(
|
|
@@ -1423,8 +1477,8 @@ class ApiGatewayIntegrationUtility:
|
|
|
1423
1477
|
"method": method,
|
|
1424
1478
|
"authorization_type": "NONE",
|
|
1425
1479
|
"cognito_available": False,
|
|
1426
|
-
"security_decision": "public_only_api"
|
|
1427
|
-
}
|
|
1480
|
+
"security_decision": "public_only_api",
|
|
1481
|
+
},
|
|
1428
1482
|
)
|
|
1429
|
-
|
|
1483
|
+
|
|
1430
1484
|
return modified_config
|
cdk_factory/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.27"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
cdk_factory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
cdk_factory/app.py,sha256=xv863N7O6HPKznB68_t7O4la9JacrkG87t9TjoDUk7s,2827
|
|
3
3
|
cdk_factory/cdk.json,sha256=SKZKhJ2PBpFH78j-F8S3VDYW-lf76--Q2I3ON-ZIQfw,3106
|
|
4
|
-
cdk_factory/version.py,sha256=
|
|
4
|
+
cdk_factory/version.py,sha256=fHi3FiqQRMkjl3o8ATyV9gZrBSNTVvt5m0WxJ-NYHTA,23
|
|
5
5
|
cdk_factory/builds/README.md,sha256=9BBWd7bXpyKdMU_g2UljhQwrC9i5O_Tvkb6oPvndoZk,90
|
|
6
6
|
cdk_factory/commands/command_loader.py,sha256=QbLquuP_AdxtlxlDy-2IWCQ6D-7qa58aphnDPtp_uTs,3744
|
|
7
7
|
cdk_factory/configurations/base_config.py,sha256=JKjhNsy0RCUZy1s8n5D_aXXI-upR9izaLtCTfKYiV9k,9624
|
|
@@ -18,7 +18,7 @@ cdk_factory/configurations/stack.py,sha256=7whhC48dUYw7BBFV49zM1Q3AghTNkaiDfy4kK
|
|
|
18
18
|
cdk_factory/configurations/workload.py,sha256=sM-B6UKOdOn5_H-eWmW03J9oa8YZZmO0bvQ69wbCM0Q,7756
|
|
19
19
|
cdk_factory/configurations/resources/_resources.py,sha256=tnXGn4kEC0JPQaTWB3QpAZG-2hIGBtugHTzuKn1OTvE,2548
|
|
20
20
|
cdk_factory/configurations/resources/api_gateway.py,sha256=-k4hMGszIdQLb5DGmWBIPy49YGutp8zczafRh-Vob0I,4904
|
|
21
|
-
cdk_factory/configurations/resources/apigateway_route_config.py,sha256=
|
|
21
|
+
cdk_factory/configurations/resources/apigateway_route_config.py,sha256=6ytn_nwKwlfpBtHL5sV6gxMpgAJ3p6QFGumMoW4CTHM,2351
|
|
22
22
|
cdk_factory/configurations/resources/auto_scaling.py,sha256=OAVl8iUdHiOYVzme1qNDwA3w2raxDNUo_W2_Vebqtx8,5005
|
|
23
23
|
cdk_factory/configurations/resources/cloudfront.py,sha256=xwDIrYQDqQMgekXSJ5vrgNXIUCfY6O8aiybE5ewwijw,1055
|
|
24
24
|
cdk_factory/configurations/resources/cloudwatch_widget.py,sha256=EdEQSXUkDtoY_Mg_cJBWo1Hp84jSiK7U9tsd3k1VhKI,1271
|
|
@@ -72,7 +72,7 @@ cdk_factory/stack/stack_module_registry.py,sha256=J14-A75VZESzRQa8p-Fepdap7Z8T7m
|
|
|
72
72
|
cdk_factory/stack/stack_modules.py,sha256=kgEK-j0smZPozVwTCfM1g1V17EyTBT0TXAQZq4vZz0o,784
|
|
73
73
|
cdk_factory/stack_library/__init__.py,sha256=5Y9TpIe8ZK1688G60PGcuP-hM0RvYEY_3Hl2qJCJJrw,581
|
|
74
74
|
cdk_factory/stack_library/stack_base.py,sha256=tTleSFmlf26DuKVF_ytftf8P7IVWb5iex8cYfYupfvQ,4940
|
|
75
|
-
cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256
|
|
75
|
+
cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256=-K9ybNHpjycw4wtaiWbMm9dLCYPYoaqlakgBIQyotCk,35632
|
|
76
76
|
cdk_factory/stack_library/auto_scaling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py,sha256=UsFqUb_3XPJAlmZ6F75nXna3elOggD1KuFmmdmhi0Lg,19070
|
|
78
78
|
cdk_factory/stack_library/aws_lambdas/lambda_stack.py,sha256=xT8-799fSXMpYaRhRKytxsbpb5EG3g2h6L822_RpRSk,22956
|
|
@@ -97,7 +97,7 @@ cdk_factory/stack_library/vpc/__init__.py,sha256=7pIqP97Gf2AJbv9Ebp1WbQGHYhgEbWJ
|
|
|
97
97
|
cdk_factory/stack_library/vpc/vpc_stack.py,sha256=zdDiGilf03esxuya5Z8zVYSVMAIuZBeD-ZKgfnEd6aw,10077
|
|
98
98
|
cdk_factory/stack_library/websites/static_website_stack.py,sha256=KBQiV6PI09mpHGtH-So5Hk3uhfFLDepoXInGbfin0cY,7938
|
|
99
99
|
cdk_factory/stages/websites/static_website_stage.py,sha256=X4fpKXkhb0zIbSHx3QyddBhVSLBryb1vf1Cg2fMTqog,755
|
|
100
|
-
cdk_factory/utilities/api_gateway_integration_utility.py,sha256=
|
|
100
|
+
cdk_factory/utilities/api_gateway_integration_utility.py,sha256=LSfw2lNtJWMsRiaHf4FLiGHRgFPm-fOUhN2YJNHtxnI,62346
|
|
101
101
|
cdk_factory/utilities/commandline_args.py,sha256=0FiNEJFbWVN8Ct7r0VHnJEx7rhUlaRKT7R7HMNJBSTI,2216
|
|
102
102
|
cdk_factory/utilities/configuration_loader.py,sha256=z0ZdGLNbTO4_yfluB9zUh_i_Poc9qj-7oRyjMRlNkN8,1522
|
|
103
103
|
cdk_factory/utilities/docker_utilities.py,sha256=9r8C-lXYpymqEfi3gTeWCQzHldvfjttPqn6p3j2khTE,8111
|
|
@@ -109,7 +109,7 @@ cdk_factory/utilities/lambda_function_utilities.py,sha256=j3tBdv_gC2MdEwBINDwAqY
|
|
|
109
109
|
cdk_factory/utilities/os_execute.py,sha256=5Op0LY_8Y-pUm04y1k8MTpNrmQvcLmQHPQITEP7EuSU,1019
|
|
110
110
|
cdk_factory/utils/api_gateway_utilities.py,sha256=If7Xu5s_UxmuV-kL3JkXxPLBdSVUKoLtohm0IUFoiV8,4378
|
|
111
111
|
cdk_factory/workload/workload_factory.py,sha256=yBUDGIuB8-5p_mGcVFxsD2ZoZIziak3yh3LL3JvS0M4,5903
|
|
112
|
-
cdk_factory-0.7.
|
|
113
|
-
cdk_factory-0.7.
|
|
114
|
-
cdk_factory-0.7.
|
|
115
|
-
cdk_factory-0.7.
|
|
112
|
+
cdk_factory-0.7.27.dist-info/METADATA,sha256=kkqu-N4uFgjOYSenuas-fjiwtIcTNoxmRK8NR6CBsyw,2451
|
|
113
|
+
cdk_factory-0.7.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
114
|
+
cdk_factory-0.7.27.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
|
|
115
|
+
cdk_factory-0.7.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|