cdk-factory 0.7.27__py3-none-any.whl → 0.7.29__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/stack_library/api_gateway/api_gateway_stack.py +47 -108
- cdk_factory/utilities/api_gateway_integration_utility.py +30 -17
- cdk_factory/version.py +1 -1
- {cdk_factory-0.7.27.dist-info → cdk_factory-0.7.29.dist-info}/METADATA +1 -1
- {cdk_factory-0.7.27.dist-info → cdk_factory-0.7.29.dist-info}/RECORD +7 -7
- {cdk_factory-0.7.27.dist-info → cdk_factory-0.7.29.dist-info}/WHEEL +0 -0
- {cdk_factory-0.7.27.dist-info → cdk_factory-0.7.29.dist-info}/licenses/LICENSE +0 -0
|
@@ -349,113 +349,36 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
349
349
|
|
|
350
350
|
def _validate_authorization_configuration(self, route, has_cognito_authorizer):
|
|
351
351
|
"""
|
|
352
|
-
Validate authorization configuration
|
|
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
|
|
352
|
+
Validate authorization configuration using the shared utility method.
|
|
353
|
+
|
|
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
|
-
|
|
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"]
|
|
362
|
+
|
|
363
|
+
api_route_config = ApiGatewayConfigRouteConfig(route_config_dict)
|
|
364
|
+
|
|
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
|
|
371
368
|
)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
logger = logging.getLogger(__name__)
|
|
376
|
-
|
|
377
|
-
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
|
378
|
-
if has_cognito_authorizer and auth_type == "NONE" and not explicit_override:
|
|
379
|
-
error_msg = (
|
|
380
|
-
f"🚨 SECURITY CONFLICT DETECTED for route {route_path} ({method}):\n"
|
|
381
|
-
f" ❌ Cognito authorizer is configured (manual or auto-import)\n"
|
|
382
|
-
f" ❌ authorization_type is set to 'NONE' (public access)\n"
|
|
383
|
-
f" ❌ This creates a security risk - public endpoint with auth available\n\n"
|
|
384
|
-
f"💡 SOLUTIONS:\n"
|
|
385
|
-
f" 1. Remove Cognito configuration if you want public access\n"
|
|
386
|
-
f" 2. Add 'allow_public_override': true to explicitly allow public access\n"
|
|
387
|
-
f" 3. Remove 'authorization_type': 'NONE' to use secure Cognito auth\n\n"
|
|
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"
|
|
390
|
-
)
|
|
391
|
-
raise ValueError(error_msg)
|
|
392
|
-
|
|
393
|
-
# Case 2: No Cognito + COGNITO explicitly requested = ERROR
|
|
394
|
-
# Only error if COGNITO was explicitly requested, not if it's the default
|
|
395
|
-
if not has_cognito_authorizer and route.get("authorization_type") == "COGNITO":
|
|
396
|
-
error_msg = (
|
|
397
|
-
f"🚨 CONFIGURATION ERROR for route {route_path} ({method}):\n"
|
|
398
|
-
f" ❌ authorization_type is explicitly set to 'COGNITO' but no Cognito authorizer configured\n"
|
|
399
|
-
f" ❌ Cannot secure endpoint without authentication provider\n\n"
|
|
400
|
-
f"💡 SOLUTIONS:\n"
|
|
401
|
-
f" 1. Add Cognito configuration to enable authentication\n"
|
|
402
|
-
f" 2. Set authorization_type to 'NONE' for public access\n"
|
|
403
|
-
f" 3. Configure SSM auto-import for user_pool_arn\n"
|
|
404
|
-
f" 4. Remove explicit authorization_type to use default behavior"
|
|
405
|
-
)
|
|
406
|
-
raise ValueError(error_msg)
|
|
407
|
-
|
|
408
|
-
# Case 3: Cognito available + NONE requested + Explicit override = WARN
|
|
409
|
-
if has_cognito_authorizer and auth_type == "NONE" and explicit_override:
|
|
410
|
-
warning_msg = (
|
|
411
|
-
f"⚠️ PUBLIC ENDPOINT CONFIGURED: {route_path} ({method})\n"
|
|
412
|
-
f" 🔓 This endpoint is intentionally public (allow_public_override: true)\n"
|
|
413
|
-
f" 🔐 Cognito authentication is available but overridden\n"
|
|
414
|
-
f" 📊 Consider monitoring this endpoint for unexpected usage patterns\n"
|
|
415
|
-
f" 🔍 Review periodically: Should this endpoint be secured?"
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
# Print to console during deployment for visibility
|
|
419
|
-
print(warning_msg)
|
|
420
|
-
|
|
421
|
-
# Structured logging for monitoring and metrics
|
|
422
|
-
logger.warning(
|
|
423
|
-
"Public endpoint configured with Cognito available",
|
|
424
|
-
extra={
|
|
425
|
-
"route": route_path,
|
|
426
|
-
"method": method,
|
|
427
|
-
"security_override": True,
|
|
428
|
-
"cognito_available": True,
|
|
429
|
-
"authorization_type": "NONE",
|
|
430
|
-
"metric_name": "public_endpoint_with_cognito",
|
|
431
|
-
"security_decision": "intentional_public",
|
|
432
|
-
"recommendation": "review_periodically",
|
|
433
|
-
},
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
# Case 4: No Cognito + NONE = INFO (expected for public-only APIs)
|
|
437
|
-
if not has_cognito_authorizer and auth_type == "NONE":
|
|
438
|
-
logger.info(
|
|
439
|
-
f"Public endpoint configured (no Cognito available): {route_path} ({method})",
|
|
440
|
-
extra={
|
|
441
|
-
"route": route_path,
|
|
442
|
-
"method": method,
|
|
443
|
-
"authorization_type": "NONE",
|
|
444
|
-
"cognito_available": False,
|
|
445
|
-
"security_decision": "public_only_api",
|
|
446
|
-
},
|
|
447
|
-
)
|
|
369
|
+
|
|
370
|
+
# Return the validated authorization type for use in the stack
|
|
371
|
+
return validated_config.authorization_type
|
|
448
372
|
|
|
449
373
|
def _setup_lambda_integration(
|
|
450
374
|
self, api_gateway, api_id, route, lambda_fn, authorizer, suffix
|
|
451
375
|
):
|
|
452
376
|
"""Setup Lambda integration for a route"""
|
|
453
|
-
import logging
|
|
454
|
-
|
|
455
377
|
route_path = route["path"]
|
|
456
|
-
|
|
378
|
+
|
|
379
|
+
# Handle authorization type fallback logic before validation
|
|
457
380
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
458
|
-
|
|
381
|
+
|
|
459
382
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
460
383
|
if (
|
|
461
384
|
not authorizer
|
|
@@ -463,14 +386,22 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
463
386
|
and "authorization_type" not in route
|
|
464
387
|
):
|
|
465
388
|
authorization_type = "NONE"
|
|
389
|
+
import logging
|
|
466
390
|
logger = logging.getLogger(__name__)
|
|
467
391
|
logger.info(
|
|
468
392
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
469
393
|
f"defaulting to public access (NONE authorization)"
|
|
470
394
|
)
|
|
471
|
-
|
|
472
|
-
#
|
|
473
|
-
|
|
395
|
+
|
|
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)
|
|
402
|
+
|
|
403
|
+
# Use the validated authorization type
|
|
404
|
+
authorization_type = validated_authorization_type
|
|
474
405
|
|
|
475
406
|
# If set to NONE (explicitly or by fallback), skip authorization
|
|
476
407
|
if authorization_type == "NONE":
|
|
@@ -487,6 +418,7 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
487
418
|
"user_pool_id": (
|
|
488
419
|
os.getenv("COGNITO_USER_POOL_ID") if authorizer else None
|
|
489
420
|
),
|
|
421
|
+
"allow_public_override": route.get("allow_public_override", False),
|
|
490
422
|
}
|
|
491
423
|
)
|
|
492
424
|
|
|
@@ -508,12 +440,11 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
508
440
|
self, api_gateway, route, lambda_fn, authorizer, api_id, suffix
|
|
509
441
|
):
|
|
510
442
|
"""Setup fallback Lambda integration for routes without src"""
|
|
511
|
-
import logging
|
|
512
|
-
|
|
513
443
|
route_path = route["path"]
|
|
514
|
-
|
|
444
|
+
|
|
445
|
+
# Handle authorization type fallback logic before validation
|
|
515
446
|
authorization_type = route.get("authorization_type", "COGNITO")
|
|
516
|
-
|
|
447
|
+
|
|
517
448
|
# If no Cognito authorizer available and default COGNITO, fall back to NONE
|
|
518
449
|
if (
|
|
519
450
|
not authorizer
|
|
@@ -521,14 +452,22 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
|
|
|
521
452
|
and "authorization_type" not in route
|
|
522
453
|
):
|
|
523
454
|
authorization_type = "NONE"
|
|
455
|
+
import logging
|
|
524
456
|
logger = logging.getLogger(__name__)
|
|
525
457
|
logger.info(
|
|
526
458
|
f"No Cognito authorizer available for route {route_path} ({route.get('method', 'unknown')}), "
|
|
527
459
|
f"defaulting to public access (NONE authorization)"
|
|
528
460
|
)
|
|
529
|
-
|
|
530
|
-
#
|
|
531
|
-
|
|
461
|
+
|
|
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
|
|
532
471
|
|
|
533
472
|
resource = (
|
|
534
473
|
api_gateway.root.resource_for_path(route_path)
|
|
@@ -1108,20 +1108,29 @@ class ApiGatewayIntegrationUtility:
|
|
|
1108
1108
|
)
|
|
1109
1109
|
http_method = "GET"
|
|
1110
1110
|
|
|
1111
|
-
#
|
|
1111
|
+
# Use the validated authorization type from api_config
|
|
1112
|
+
auth_type = api_config.authorization_type
|
|
1113
|
+
method_props = {
|
|
1114
|
+
"http_method": http_method,
|
|
1115
|
+
"resource_id": resource.resource_id,
|
|
1116
|
+
"rest_api_id": api_gateway.rest_api_id,
|
|
1117
|
+
"authorization_type": auth_type,
|
|
1118
|
+
"api_key_required": api_config.api_key_required,
|
|
1119
|
+
"request_parameters": api_config.request_parameters,
|
|
1120
|
+
"integration": integration_props,
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
# Only add authorizer_id if authorization type is not NONE
|
|
1124
|
+
if auth_type != "NONE":
|
|
1125
|
+
method_props["authorizer_id"] = self._get_existing_authorizer_id_with_ssm_fallback(
|
|
1126
|
+
api_config, stack_config
|
|
1127
|
+
)
|
|
1128
|
+
|
|
1129
|
+
# Create method using L1 construct with validated authorization configuration
|
|
1112
1130
|
method = apigateway.CfnMethod(
|
|
1113
1131
|
self.scope,
|
|
1114
1132
|
f"method-{http_method.lower()}-{resource.node.id}-existing-auth",
|
|
1115
|
-
|
|
1116
|
-
resource_id=resource.resource_id,
|
|
1117
|
-
rest_api_id=api_gateway.rest_api_id,
|
|
1118
|
-
authorization_type="COGNITO_USER_POOLS",
|
|
1119
|
-
authorizer_id=self._get_existing_authorizer_id_with_ssm_fallback(
|
|
1120
|
-
api_config, stack_config
|
|
1121
|
-
),
|
|
1122
|
-
api_key_required=api_config.api_key_required,
|
|
1123
|
-
request_parameters=api_config.request_parameters,
|
|
1124
|
-
integration=integration_props,
|
|
1133
|
+
**method_props
|
|
1125
1134
|
)
|
|
1126
1135
|
|
|
1127
1136
|
# Add Lambda permission for API Gateway to invoke the function
|
|
@@ -1382,15 +1391,19 @@ class ApiGatewayIntegrationUtility:
|
|
|
1382
1391
|
modified_config = deepcopy(api_config)
|
|
1383
1392
|
|
|
1384
1393
|
auth_type = str(getattr(api_config, "authorization_type", "COGNITO")).upper()
|
|
1385
|
-
|
|
1386
|
-
# Check for explicit override flag
|
|
1387
|
-
explicit_override = (
|
|
1388
|
-
str(getattr(api_config, "allow_public_override", False)).lower() == "true"
|
|
1389
|
-
)
|
|
1390
|
-
|
|
1391
1394
|
route_path = getattr(api_config, "routes", "unknown")
|
|
1392
1395
|
method = getattr(api_config, "method", "unknown")
|
|
1396
|
+
|
|
1397
|
+
logger = logging.getLogger(__name__)
|
|
1393
1398
|
|
|
1399
|
+
# Check for explicit override flag
|
|
1400
|
+
explicit_override = getattr(api_config, "allow_public_override", False)
|
|
1401
|
+
# Handle both boolean and string values
|
|
1402
|
+
if isinstance(explicit_override, str):
|
|
1403
|
+
explicit_override = explicit_override.lower() in ("true", "1", "yes")
|
|
1404
|
+
else:
|
|
1405
|
+
explicit_override = bool(explicit_override)
|
|
1406
|
+
|
|
1394
1407
|
logger = logging.getLogger(__name__)
|
|
1395
1408
|
|
|
1396
1409
|
# Case 1: Cognito available + NONE requested + No explicit override = ERROR
|
cdk_factory/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.29"
|
|
@@ -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=XdC0R1utqmwH52az-uz3mk0vLZyV2OyWiin3soRIguo,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
|
|
@@ -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=xzKOdoKrd8AxuBWtV8uFa3r6I7wSKdC74m7tewBhzT8,62933
|
|
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.29.dist-info/METADATA,sha256=uBLNGvVXNfeVMl5IMIJfZX2S0dLDrPVnUqlSd0Dec9Y,2451
|
|
113
|
+
cdk_factory-0.7.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
114
|
+
cdk_factory-0.7.29.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
|
|
115
|
+
cdk_factory-0.7.29.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|