cdk-factory 0.7.26__py3-none-any.whl → 0.7.28__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.
Potentially problematic release.
This version of cdk-factory might be problematic. Click here for more details.
- cdk_factory/configurations/resources/apigateway_route_config.py +1 -1
- cdk_factory/stack_library/api_gateway/api_gateway_stack.py +50 -100
- cdk_factory/utilities/api_gateway_integration_utility.py +195 -137
- cdk_factory/version.py +1 -1
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.28.dist-info}/METADATA +1 -1
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.28.dist-info}/RECORD +8 -8
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.28.dist-info}/WHEEL +0 -0
- {cdk_factory-0.7.26.dist-info → cdk_factory-0.7.28.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]:
|
|
@@ -349,122 +349,60 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
349
349
|
|
|
350
350
|
def _validate_authorization_configuration(self, route, has_cognito_authorizer):
|
|
351
351
|
"""
|
|
352
|
-
Validate authorization configuration
|
|
352
|
+
Validate authorization configuration using the shared utility method.
|
|
353
353
|
|
|
354
|
-
This
|
|
355
|
-
|
|
356
|
-
- If Cognito is not available and route wants COGNITO auth, raises error
|
|
357
|
-
- Provides verbose warnings for monitoring and security awareness
|
|
358
|
-
|
|
359
|
-
Args:
|
|
360
|
-
route (dict): Route configuration
|
|
361
|
-
has_cognito_authorizer (bool): Whether a Cognito authorizer is configured
|
|
362
|
-
|
|
363
|
-
Raises:
|
|
364
|
-
ValueError: When there are security conflicts without explicit overrides
|
|
354
|
+
This delegates to the ApiGatewayIntegrationUtility for consistent validation
|
|
355
|
+
across both API Gateway stack and Lambda stack patterns.
|
|
365
356
|
"""
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
method = route.get("method", "unknown")
|
|
357
|
+
# Convert route dict to ApiGatewayConfigRouteConfig for utility validation
|
|
358
|
+
# Map "path" to "route" for compatibility with the config object
|
|
359
|
+
route_config_dict = dict(route) # Create a copy
|
|
360
|
+
if "path" in route_config_dict:
|
|
361
|
+
route_config_dict["route"] = route_config_dict["path"]
|
|
372
362
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
|
376
|
-
if has_cognito_authorizer and auth_type == "NONE" and not explicit_override:
|
|
377
|
-
error_msg = (
|
|
378
|
-
f"🚨 SECURITY CONFLICT DETECTED for route {route_path} ({method}):\n"
|
|
379
|
-
f" ❌ Cognito authorizer is configured (manual or auto-import)\n"
|
|
380
|
-
f" ❌ authorization_type is set to 'NONE' (public access)\n"
|
|
381
|
-
f" ❌ This creates a security risk - public endpoint with auth available\n\n"
|
|
382
|
-
f"💡 SOLUTIONS:\n"
|
|
383
|
-
f" 1. Remove Cognito configuration if you want public access\n"
|
|
384
|
-
f" 2. Add 'allow_public_override': true to explicitly allow public access\n"
|
|
385
|
-
f" 3. Remove 'authorization_type': 'NONE' to use secure Cognito auth\n\n"
|
|
386
|
-
f"🔒 This prevents accidental public endpoints when authentication is available."
|
|
387
|
-
)
|
|
388
|
-
raise ValueError(error_msg)
|
|
363
|
+
api_route_config = ApiGatewayConfigRouteConfig(route_config_dict)
|
|
389
364
|
|
|
390
|
-
#
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
f"🚨 CONFIGURATION ERROR for route {route_path} ({method}):\n"
|
|
395
|
-
f" ❌ authorization_type is explicitly set to 'COGNITO' but no Cognito authorizer configured\n"
|
|
396
|
-
f" ❌ Cannot secure endpoint without authentication provider\n\n"
|
|
397
|
-
f"💡 SOLUTIONS:\n"
|
|
398
|
-
f" 1. Add Cognito configuration to enable authentication\n"
|
|
399
|
-
f" 2. Set authorization_type to 'NONE' for public access\n"
|
|
400
|
-
f" 3. Configure SSM auto-import for user_pool_arn\n"
|
|
401
|
-
f" 4. Remove explicit authorization_type to use default behavior"
|
|
402
|
-
)
|
|
403
|
-
raise ValueError(error_msg)
|
|
404
|
-
|
|
405
|
-
# Case 3: Cognito available + NONE requested + Explicit override = WARN
|
|
406
|
-
if has_cognito_authorizer and auth_type == "NONE" and explicit_override:
|
|
407
|
-
warning_msg = (
|
|
408
|
-
f"⚠️ PUBLIC ENDPOINT CONFIGURED: {route_path} ({method})\n"
|
|
409
|
-
f" 🔓 This endpoint is intentionally public (allow_public_override: true)\n"
|
|
410
|
-
f" 🔐 Cognito authentication is available but overridden\n"
|
|
411
|
-
f" 📊 Consider monitoring this endpoint for unexpected usage patterns\n"
|
|
412
|
-
f" 🔍 Review periodically: Should this endpoint be secured?"
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
# Print to console during deployment for visibility
|
|
416
|
-
print(warning_msg)
|
|
417
|
-
|
|
418
|
-
# Structured logging for monitoring and metrics
|
|
419
|
-
logger.warning(
|
|
420
|
-
"Public endpoint configured with Cognito available",
|
|
421
|
-
extra={
|
|
422
|
-
"route": route_path,
|
|
423
|
-
"method": method,
|
|
424
|
-
"security_override": True,
|
|
425
|
-
"cognito_available": True,
|
|
426
|
-
"authorization_type": "NONE",
|
|
427
|
-
"metric_name": "public_endpoint_with_cognito",
|
|
428
|
-
"security_decision": "intentional_public",
|
|
429
|
-
"recommendation": "review_periodically"
|
|
430
|
-
}
|
|
431
|
-
)
|
|
365
|
+
# Use the utility's enhanced validation method
|
|
366
|
+
validated_config = self.integration_utility._validate_and_adjust_authorization_configuration(
|
|
367
|
+
api_route_config, has_cognito_authorizer
|
|
368
|
+
)
|
|
432
369
|
|
|
433
|
-
#
|
|
434
|
-
|
|
435
|
-
logger.info(
|
|
436
|
-
f"Public endpoint configured (no Cognito available): {route_path} ({method})",
|
|
437
|
-
extra={
|
|
438
|
-
"route": route_path,
|
|
439
|
-
"method": method,
|
|
440
|
-
"authorization_type": "NONE",
|
|
441
|
-
"cognito_available": False,
|
|
442
|
-
"security_decision": "public_only_api"
|
|
443
|
-
}
|
|
444
|
-
)
|
|
370
|
+
# Return the validated authorization type for use in the stack
|
|
371
|
+
return validated_config.authorization_type
|
|
445
372
|
|
|
446
373
|
def _setup_lambda_integration(
|
|
447
374
|
self, api_gateway, api_id, route, lambda_fn, authorizer, suffix
|
|
448
375
|
):
|
|
449
376
|
"""Setup Lambda integration for a route"""
|
|
450
|
-
import logging
|
|
451
|
-
|
|
452
377
|
route_path = route["path"]
|
|
453
|
-
|
|
378
|
+
|
|
379
|
+
# Handle authorization type fallback logic before validation
|
|
454
380
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
455
381
|
|
|
456
382
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
457
|
-
if
|
|
383
|
+
if (
|
|
384
|
+
not authorizer
|
|
385
|
+
and authorization_type == "COGNITO"
|
|
386
|
+
and "authorization_type" not in route
|
|
387
|
+
):
|
|
458
388
|
authorization_type = "NONE"
|
|
389
|
+
import logging
|
|
459
390
|
logger = logging.getLogger(__name__)
|
|
460
391
|
logger.info(
|
|
461
392
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
462
393
|
f"defaulting to public access (NONE authorization)"
|
|
463
394
|
)
|
|
464
395
|
|
|
465
|
-
#
|
|
466
|
-
|
|
396
|
+
# Create a route config with the resolved authorization type for validation
|
|
397
|
+
route_for_validation = dict(route)
|
|
398
|
+
route_for_validation["authorization_type"] = authorization_type
|
|
399
|
+
|
|
400
|
+
# Validate authorization configuration using the utility
|
|
401
|
+
validated_authorization_type = self._validate_authorization_configuration(route_for_validation, authorizer is not None)
|
|
467
402
|
|
|
403
|
+
# Use the validated authorization type
|
|
404
|
+
authorization_type = validated_authorization_type
|
|
405
|
+
|
|
468
406
|
# If set to NONE (explicitly or by fallback), skip authorization
|
|
469
407
|
if authorization_type == "NONE":
|
|
470
408
|
authorizer = None
|
|
@@ -480,6 +418,7 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
480
418
|
"user_pool_id": (
|
|
481
419
|
os.getenv("COGNITO_USER_POOL_ID") if authorizer else None
|
|
482
420
|
),
|
|
421
|
+
"allow_public_override": route.get("allow_public_override", False),
|
|
483
422
|
}
|
|
484
423
|
)
|
|
485
424
|
|
|
@@ -501,23 +440,34 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
501
440
|
self, api_gateway, route, lambda_fn, authorizer, api_id, suffix
|
|
502
441
|
):
|
|
503
442
|
"""Setup fallback Lambda integration for routes without src"""
|
|
504
|
-
import logging
|
|
505
|
-
|
|
506
443
|
route_path = route["path"]
|
|
507
|
-
|
|
444
|
+
|
|
445
|
+
# Handle authorization type fallback logic before validation
|
|
508
446
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
509
447
|
|
|
510
448
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
511
|
-
if
|
|
449
|
+
if (
|
|
450
|
+
not authorizer
|
|
451
|
+
and authorization_type == "COGNITO"
|
|
452
|
+
and "authorization_type" not in route
|
|
453
|
+
):
|
|
512
454
|
authorization_type = "NONE"
|
|
455
|
+
import logging
|
|
513
456
|
logger = logging.getLogger(__name__)
|
|
514
457
|
logger.info(
|
|
515
458
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
516
459
|
f"defaulting to public access (NONE authorization)"
|
|
517
460
|
)
|
|
518
461
|
|
|
519
|
-
#
|
|
520
|
-
|
|
462
|
+
# Create a route config with the resolved authorization type for validation
|
|
463
|
+
route_for_validation = dict(route)
|
|
464
|
+
route_for_validation["authorization_type"] = authorization_type
|
|
465
|
+
|
|
466
|
+
# Validate authorization configuration using the utility
|
|
467
|
+
validated_authorization_type = self._validate_authorization_configuration(route_for_validation, authorizer is not None)
|
|
468
|
+
|
|
469
|
+
# Use the validated authorization type
|
|
470
|
+
authorization_type = validated_authorization_type
|
|
521
471
|
|
|
522
472
|
resource = (
|
|
523
473
|
api_gateway.root.resource_for_path(route_path)
|
|
@@ -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,45 @@ 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)
|
|
1383
|
+
|
|
1384
|
+
auth_type = str(getattr(api_config, "authorization_type", "COGNITO")).upper()
|
|
1385
|
+
route_path = getattr(api_config, "routes", "unknown")
|
|
1386
|
+
method = getattr(api_config, "method", "unknown")
|
|
1336
1387
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1388
|
+
logger = logging.getLogger(__name__)
|
|
1389
|
+
|
|
1339
1390
|
# Check for explicit override flag
|
|
1340
|
-
explicit_override = getattr(api_config,
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1391
|
+
explicit_override = getattr(api_config, "allow_public_override", False)
|
|
1392
|
+
# Handle both boolean and string values
|
|
1393
|
+
if isinstance(explicit_override, str):
|
|
1394
|
+
explicit_override = explicit_override.lower() in ("true", "1", "yes")
|
|
1395
|
+
else:
|
|
1396
|
+
explicit_override = bool(explicit_override)
|
|
1344
1397
|
|
|
1345
1398
|
logger = logging.getLogger(__name__)
|
|
1346
|
-
|
|
1399
|
+
|
|
1347
1400
|
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
|
1348
1401
|
if has_cognito_authorizer and auth_type == "NONE" and not explicit_override:
|
|
1349
1402
|
error_msg = (
|
|
@@ -1355,16 +1408,17 @@ class ApiGatewayIntegrationUtility:
|
|
|
1355
1408
|
f" 1. Remove Cognito configuration if you want public access\n"
|
|
1356
1409
|
f" 2. Add 'allow_public_override': true to explicitly allow public access\n"
|
|
1357
1410
|
f" 3. Remove 'authorization_type': 'NONE' to use secure Cognito auth\n\n"
|
|
1358
|
-
f"🔒 This prevents accidental public endpoints when authentication is available
|
|
1411
|
+
f"🔒 This prevents accidental public endpoints when authentication is available.\n\n"
|
|
1412
|
+
f"👉 ApiGatewayIntegrationUtility documentation for more details: https://github.com/your-repo/api-gateway-stack"
|
|
1359
1413
|
)
|
|
1360
1414
|
raise ValueError(error_msg)
|
|
1361
|
-
|
|
1362
|
-
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
1415
|
+
|
|
1416
|
+
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
1363
1417
|
# Only error if COGNITO was explicitly requested, not if it's the default
|
|
1364
1418
|
original_auth_type = None
|
|
1365
|
-
if hasattr(api_config,
|
|
1366
|
-
original_auth_type = api_config.dictionary.get(
|
|
1367
|
-
|
|
1419
|
+
if hasattr(api_config, "dictionary") and api_config.dictionary:
|
|
1420
|
+
original_auth_type = api_config.dictionary.get("authorization_type")
|
|
1421
|
+
|
|
1368
1422
|
if not has_cognito_authorizer and original_auth_type == "COGNITO":
|
|
1369
1423
|
error_msg = (
|
|
1370
1424
|
f"🚨 CONFIGURATION ERROR for route {route_path} ({method}):\n"
|
|
@@ -1377,7 +1431,7 @@ class ApiGatewayIntegrationUtility:
|
|
|
1377
1431
|
f" 4. Remove explicit authorization_type to use default behavior"
|
|
1378
1432
|
)
|
|
1379
1433
|
raise ValueError(error_msg)
|
|
1380
|
-
|
|
1434
|
+
|
|
1381
1435
|
# Case 3: Cognito available + NONE requested + Explicit override = WARN
|
|
1382
1436
|
if has_cognito_authorizer and auth_type == "NONE" and explicit_override:
|
|
1383
1437
|
warning_msg = (
|
|
@@ -1387,10 +1441,10 @@ class ApiGatewayIntegrationUtility:
|
|
|
1387
1441
|
f" 📊 Consider monitoring this endpoint for unexpected usage patterns\n"
|
|
1388
1442
|
f" 🔍 Review periodically: Should this endpoint be secured?"
|
|
1389
1443
|
)
|
|
1390
|
-
|
|
1444
|
+
|
|
1391
1445
|
# Print to console during deployment for visibility
|
|
1392
1446
|
print(warning_msg)
|
|
1393
|
-
|
|
1447
|
+
|
|
1394
1448
|
# Structured logging for monitoring and metrics
|
|
1395
1449
|
logger.warning(
|
|
1396
1450
|
"Public endpoint configured with Cognito available",
|
|
@@ -1402,18 +1456,22 @@ class ApiGatewayIntegrationUtility:
|
|
|
1402
1456
|
"authorization_type": "NONE",
|
|
1403
1457
|
"metric_name": "public_endpoint_with_cognito",
|
|
1404
1458
|
"security_decision": "intentional_public",
|
|
1405
|
-
"recommendation": "review_periodically"
|
|
1406
|
-
}
|
|
1459
|
+
"recommendation": "review_periodically",
|
|
1460
|
+
},
|
|
1407
1461
|
)
|
|
1408
|
-
|
|
1462
|
+
|
|
1409
1463
|
# Case 4: No Cognito + default COGNITO = Fall back to NONE
|
|
1410
|
-
if
|
|
1464
|
+
if (
|
|
1465
|
+
not has_cognito_authorizer
|
|
1466
|
+
and auth_type == "COGNITO"
|
|
1467
|
+
and original_auth_type is None
|
|
1468
|
+
):
|
|
1411
1469
|
modified_config.authorization_type = "NONE"
|
|
1412
1470
|
logger.info(
|
|
1413
1471
|
f"No Cognito authorizer available for route {route_path} ({method}), "
|
|
1414
1472
|
f"defaulting to public access (NONE authorization)"
|
|
1415
1473
|
)
|
|
1416
|
-
|
|
1474
|
+
|
|
1417
1475
|
# Case 5: No Cognito + NONE = INFO (expected for public-only APIs)
|
|
1418
1476
|
if not has_cognito_authorizer and auth_type == "NONE":
|
|
1419
1477
|
logger.info(
|
|
@@ -1423,8 +1481,8 @@ class ApiGatewayIntegrationUtility:
|
|
|
1423
1481
|
"method": method,
|
|
1424
1482
|
"authorization_type": "NONE",
|
|
1425
1483
|
"cognito_available": False,
|
|
1426
|
-
"security_decision": "public_only_api"
|
|
1427
|
-
}
|
|
1484
|
+
"security_decision": "public_only_api",
|
|
1485
|
+
},
|
|
1428
1486
|
)
|
|
1429
|
-
|
|
1487
|
+
|
|
1430
1488
|
return modified_config
|
cdk_factory/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.28"
|
|
@@ -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=zxRa3gUEpxj8fTU5qOT60NDmCfmdbg7_Z6ZkpKAhrNg,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=83oV1pSFfb68mH4CH3mz0SERiiihpbPCsKK9zHgjvyE,32490
|
|
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=LvsgUaipghTte4FZj1xHRn_O1KoFJGivGhtHxFJI2sc,62607
|
|
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.28.dist-info/METADATA,sha256=kkMbOLCrFJA_nNSeJiE_s3w6egr9KlKXq2etML92R1U,2451
|
|
113
|
+
cdk_factory-0.7.28.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
114
|
+
cdk_factory-0.7.28.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
|
|
115
|
+
cdk_factory-0.7.28.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|