cdk-factory 0.16.15__py3-none-any.whl → 0.20.0__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.

Files changed (66) hide show
  1. cdk_factory/configurations/base_config.py +23 -24
  2. cdk_factory/configurations/cdk_config.py +1 -1
  3. cdk_factory/configurations/deployment.py +12 -0
  4. cdk_factory/configurations/devops.py +1 -1
  5. cdk_factory/configurations/resources/acm.py +9 -2
  6. cdk_factory/configurations/resources/auto_scaling.py +7 -5
  7. cdk_factory/configurations/resources/cloudfront.py +7 -2
  8. cdk_factory/configurations/resources/ecr.py +1 -1
  9. cdk_factory/configurations/resources/ecs_cluster.py +12 -5
  10. cdk_factory/configurations/resources/ecs_service.py +30 -3
  11. cdk_factory/configurations/resources/lambda_edge.py +18 -4
  12. cdk_factory/configurations/resources/load_balancer.py +8 -9
  13. cdk_factory/configurations/resources/monitoring.py +8 -3
  14. cdk_factory/configurations/resources/rds.py +8 -9
  15. cdk_factory/configurations/resources/route53.py +5 -0
  16. cdk_factory/configurations/resources/rum.py +7 -2
  17. cdk_factory/configurations/resources/s3.py +10 -2
  18. cdk_factory/configurations/resources/security_group_full_stack.py +7 -8
  19. cdk_factory/configurations/resources/vpc.py +19 -0
  20. cdk_factory/configurations/workload.py +32 -2
  21. cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +1 -1
  22. cdk_factory/constructs/ecr/ecr_construct.py +9 -2
  23. cdk_factory/constructs/lambdas/policies/policy_docs.py +4 -4
  24. cdk_factory/interfaces/istack.py +4 -4
  25. cdk_factory/interfaces/networked_stack_mixin.py +6 -6
  26. cdk_factory/interfaces/standardized_ssm_mixin.py +684 -0
  27. cdk_factory/interfaces/vpc_provider_mixin.py +64 -33
  28. cdk_factory/lambdas/edge/ip_gate/handler.py +42 -40
  29. cdk_factory/pipeline/pipeline_factory.py +3 -3
  30. cdk_factory/stack_library/__init__.py +3 -2
  31. cdk_factory/stack_library/acm/acm_stack.py +7 -17
  32. cdk_factory/stack_library/api_gateway/api_gateway_stack.py +84 -59
  33. cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +454 -537
  34. cdk_factory/stack_library/cloudfront/cloudfront_stack.py +76 -22
  35. cdk_factory/stack_library/code_artifact/code_artifact_stack.py +5 -27
  36. cdk_factory/stack_library/cognito/cognito_stack.py +152 -92
  37. cdk_factory/stack_library/dynamodb/dynamodb_stack.py +19 -15
  38. cdk_factory/stack_library/ecr/ecr_stack.py +2 -2
  39. cdk_factory/stack_library/ecs/__init__.py +1 -3
  40. cdk_factory/stack_library/ecs/ecs_cluster_stack.py +159 -75
  41. cdk_factory/stack_library/ecs/ecs_service_stack.py +59 -52
  42. cdk_factory/stack_library/lambda_edge/EDGE_LOG_RETENTION_TODO.md +226 -0
  43. cdk_factory/stack_library/lambda_edge/LAMBDA_EDGE_LOG_RETENTION_BLOG.md +215 -0
  44. cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +240 -83
  45. cdk_factory/stack_library/load_balancer/load_balancer_stack.py +139 -212
  46. cdk_factory/stack_library/rds/rds_stack.py +74 -98
  47. cdk_factory/stack_library/route53/route53_stack.py +246 -40
  48. cdk_factory/stack_library/rum/rum_stack.py +108 -91
  49. cdk_factory/stack_library/security_group/security_group_full_stack.py +10 -53
  50. cdk_factory/stack_library/security_group/security_group_stack.py +12 -19
  51. cdk_factory/stack_library/simple_queue_service/sqs_stack.py +1 -34
  52. cdk_factory/stack_library/stack_base.py +5 -0
  53. cdk_factory/stack_library/vpc/vpc_stack.py +171 -130
  54. cdk_factory/stack_library/websites/static_website_stack.py +7 -3
  55. cdk_factory/utilities/api_gateway_integration_utility.py +24 -16
  56. cdk_factory/utilities/environment_services.py +5 -5
  57. cdk_factory/utilities/json_loading_utility.py +1 -1
  58. cdk_factory/validation/config_validator.py +483 -0
  59. cdk_factory/version.py +1 -1
  60. {cdk_factory-0.16.15.dist-info → cdk_factory-0.20.0.dist-info}/METADATA +1 -1
  61. {cdk_factory-0.16.15.dist-info → cdk_factory-0.20.0.dist-info}/RECORD +64 -62
  62. cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -321
  63. cdk_factory/interfaces/ssm_parameter_mixin.py +0 -454
  64. {cdk_factory-0.16.15.dist-info → cdk_factory-0.20.0.dist-info}/WHEEL +0 -0
  65. {cdk_factory-0.16.15.dist-info → cdk_factory-0.20.0.dist-info}/entry_points.txt +0 -0
  66. {cdk_factory-0.16.15.dist-info → cdk_factory-0.20.0.dist-info}/licenses/LICENSE +0 -0
@@ -16,7 +16,7 @@ from cdk_factory.configurations.deployment import DeploymentConfig
16
16
  from cdk_factory.configurations.resources.rum import RumConfig
17
17
  from cdk_factory.configurations.stack import StackConfig
18
18
  from cdk_factory.interfaces.istack import IStack
19
- from cdk_factory.interfaces.enhanced_ssm_parameter_mixin import EnhancedSsmParameterMixin
19
+ from cdk_factory.interfaces.standardized_ssm_mixin import StandardizedSsmMixin
20
20
  from cdk_factory.stack.stack_module_registry import register_stack
21
21
  from cdk_factory.workload.workload_factory import WorkloadConfig
22
22
 
@@ -25,7 +25,7 @@ logger = Logger(__name__)
25
25
 
26
26
  @register_stack("rum_library_module")
27
27
  @register_stack("rum_stack")
28
- class RumStack(IStack, EnhancedSsmParameterMixin):
28
+ class RumStack(IStack, StandardizedSsmMixin):
29
29
  """
30
30
  RUM Stack - Creates a CloudWatch RUM app monitor with optional Cognito integration.
31
31
  Can either use existing Cognito resources or create new ones if not provided.
@@ -51,17 +51,37 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
51
51
  self.stack_config = stack_config
52
52
  self.deployment = deployment
53
53
  self.rum_config = RumConfig(stack_config.dictionary.get("rum", {}))
54
-
54
+
55
55
  logger.info(f"Building RUM stack: {self.rum_config.name}")
56
56
 
57
57
  # Setup enhanced SSM integration
58
- self.setup_enhanced_ssm_integration(
58
+ rum_config = stack_config.dictionary.get("rum", {}).copy()
59
+
60
+ # Configure SSM imports for cognito resources if needed
61
+ if not self.rum_config.cognito_identity_pool_id:
62
+ # Only add SSM imports if we have the required template variables
63
+ # Check if deployment has organization info for template resolution
64
+ if (hasattr(deployment, 'organization') and deployment.organization and
65
+ hasattr(deployment, 'environment') and deployment.environment):
66
+ # Add explicit import path for cognito identity pool using new pattern
67
+ if "ssm" not in rum_config:
68
+ rum_config["ssm"] = {}
69
+ if "imports" not in rum_config["ssm"]:
70
+ rum_config["ssm"]["imports"] = {}
71
+ rum_config["ssm"]["imports"][
72
+ "cognito_identity_pool_id"
73
+ ] = "/{{ORGANIZATION}}/{{ENVIRONMENT}}/cognito/user-pool/identity-pool-id"
74
+
75
+ self.setup_ssm_integration(
59
76
  scope=self,
60
- config=stack_config.dictionary.get("rum", {}),
77
+ config=rum_config,
61
78
  resource_type="rum",
62
- resource_name=self.rum_config.name
79
+ resource_name=self.rum_config.name,
63
80
  )
64
81
 
82
+ # Process SSM imports using standardized method
83
+ self.process_ssm_imports()
84
+
65
85
  # Import or create Cognito resources
66
86
  identity_pool_id, guest_role_arn = self._setup_cognito_integration()
67
87
 
@@ -84,14 +104,14 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
84
104
  identity_pool_id = self.rum_config.cognito_identity_pool_id
85
105
  logger.info(f"Using existing Cognito Identity Pool: {identity_pool_id}")
86
106
  else:
87
- # Try to import from SSM using enhanced SSM pattern
88
- imported_values = self.auto_import_resources({
89
- "cognito_identity_pool_id": "auto"
90
- })
91
-
92
- if imported_values.get("cognito_identity_pool_id"):
93
- identity_pool_id = imported_values["cognito_identity_pool_id"]
94
- logger.info(f"Imported Cognito Identity Pool from SSM: {identity_pool_id}")
107
+ # Try to import from SSM using standardized approach
108
+ cognito_identity_pool_id = self.get_ssm_imported_value("cognito_identity_pool_id")
109
+
110
+ if cognito_identity_pool_id:
111
+ identity_pool_id = cognito_identity_pool_id
112
+ logger.info(
113
+ f"Imported Cognito Identity Pool from SSM: {identity_pool_id}"
114
+ )
95
115
 
96
116
  # If no existing identity pool found, create new Cognito resources
97
117
  if not identity_pool_id and self.rum_config.create_cognito_identity_pool:
@@ -107,17 +127,21 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
107
127
  """Create new Cognito User Pool and Identity Pool for RUM"""
108
128
  logger.info("Creating new Cognito resources for RUM")
109
129
 
130
+ def _resource_name(name: str) -> str:
131
+ """Helper to generate resource names"""
132
+ return f"{self.rum_config.name}-{name}"
133
+
110
134
  # Create User Pool if needed
111
135
  user_pool_id = self.rum_config.cognito_user_pool_id
112
136
  if not user_pool_id and self.rum_config.create_cognito_user_pool:
113
137
  self.user_pool = cognito.UserPool(
114
138
  self,
115
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-user-pool"),
139
+ id=_resource_name("user-pool"),
116
140
  user_pool_name=self.rum_config.cognito_user_pool_name,
117
141
  self_sign_up_enabled=True,
118
142
  sign_in_aliases=cognito.SignInAliases(email=True),
119
143
  auto_verify=cognito.AutoVerifiedAttrs(email=True),
120
- removal_policy=cdk.RemovalPolicy.DESTROY
144
+ removal_policy=cdk.RemovalPolicy.DESTROY,
121
145
  )
122
146
  user_pool_id = self.user_pool.user_pool_id
123
147
  logger.info(f"Created Cognito User Pool: {user_pool_id}")
@@ -128,33 +152,34 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
128
152
  # Create User Pool Client for Identity Pool integration
129
153
  user_pool_client = cognito.UserPoolClient(
130
154
  self,
131
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-user-pool-client"),
155
+ id=_resource_name("user-pool-client"),
132
156
  user_pool=self.user_pool,
133
157
  generate_secret=False,
134
- auth_flows=cognito.AuthFlow(
135
- user_srp=True,
136
- user_password=True
137
- )
158
+ auth_flows=cognito.AuthFlow(user_srp=True, user_password=True),
159
+ )
160
+
161
+ identity_pool_providers.append(
162
+ {
163
+ "providerName": f"cognito-idp.{self.region}.amazonaws.com/{user_pool_id}",
164
+ "providerType": "COGNITO_USER_POOLS",
165
+ "clientId": user_pool_client.user_pool_client_id,
166
+ }
138
167
  )
139
-
140
- identity_pool_providers.append({
141
- "providerName": f"cognito-idp.{self.region}.amazonaws.com/{user_pool_id}",
142
- "providerType": "COGNITO_USER_POOLS",
143
- "clientId": user_pool_client.user_pool_client_id
144
- })
145
168
 
146
169
  self.identity_pool = cognito.CfnIdentityPool(
147
170
  self,
148
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-identity-pool"),
171
+ id=_resource_name("identity-pool"),
149
172
  identity_pool_name=self.rum_config.cognito_identity_pool_name,
150
173
  allow_unauthenticated_identities=True,
151
- cognito_identity_providers=identity_pool_providers if identity_pool_providers else None
174
+ cognito_identity_providers=(
175
+ identity_pool_providers if identity_pool_providers else None
176
+ ),
152
177
  )
153
178
 
154
179
  # Create IAM role for unauthenticated users (guest role)
155
180
  guest_role = iam.Role(
156
181
  self,
157
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-guest-role"),
182
+ id=_resource_name("guest-role"),
158
183
  assumed_by=iam.FederatedPrincipal(
159
184
  "cognito-identity.amazonaws.com",
160
185
  conditions={
@@ -163,52 +188,55 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
163
188
  },
164
189
  "ForAnyValue:StringLike": {
165
190
  "cognito-identity.amazonaws.com:amr": "unauthenticated"
166
- }
167
- }
191
+ },
192
+ },
168
193
  ),
169
194
  inline_policies={
170
195
  "RUMPolicy": iam.PolicyDocument(
171
196
  statements=[
172
197
  iam.PolicyStatement(
173
198
  effect=iam.Effect.ALLOW,
174
- actions=[
175
- "rum:PutRumEvents"
199
+ actions=["rum:PutRumEvents"],
200
+ resources=[
201
+ f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"
176
202
  ],
177
- resources=[f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"]
178
203
  )
179
204
  ]
180
205
  )
181
- }
206
+ },
182
207
  )
183
208
 
184
209
  # Attach the role to the identity pool
185
210
  cognito.CfnIdentityPoolRoleAttachment(
186
211
  self,
187
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-role-attachment"),
212
+ id=_resource_name("role-attachment"),
188
213
  identity_pool_id=self.identity_pool.ref,
189
- roles={
190
- "unauthenticated": guest_role.role_arn
191
- }
214
+ roles={"unauthenticated": guest_role.role_arn},
192
215
  )
193
216
 
194
217
  logger.info(f"Created Cognito Identity Pool: {self.identity_pool.ref}")
195
218
  return self.identity_pool.ref, guest_role.role_arn
196
219
 
197
220
  def _create_minimal_identity_pool(self) -> tuple[str, str]:
198
- """Create a minimal identity pool for RUM when no Cognito resources are provided"""
221
+ """Create a minimal Identity Pool with just a guest role for RUM"""
199
222
  logger.info("Creating minimal Cognito Identity Pool for RUM")
200
223
 
201
- self.identity_pool = cognito.CfnIdentityPool(
224
+ def _resource_name(name: str) -> str:
225
+ """Helper to generate resource names"""
226
+ return f"{self.rum_config.name}-{name}"
227
+
228
+ # Create minimal Identity Pool
229
+ minimal_identity_pool = cognito.CfnIdentityPool(
202
230
  self,
203
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-identity-pool"),
231
+ id=_resource_name("minimal-identity-pool"),
204
232
  identity_pool_name=f"{self.rum_config.name}_minimal_identity_pool",
205
- allow_unauthenticated_identities=True
233
+ allow_unauthenticated_identities=True,
206
234
  )
207
235
 
208
236
  # Create minimal IAM role for unauthenticated users
209
237
  guest_role = iam.Role(
210
238
  self,
211
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-guest-role"),
239
+ id=_resource_name("minimal-guest-role"),
212
240
  assumed_by=iam.FederatedPrincipal(
213
241
  "cognito-identity.amazonaws.com",
214
242
  conditions={
@@ -217,85 +245,74 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
217
245
  },
218
246
  "ForAnyValue:StringLike": {
219
247
  "cognito-identity.amazonaws.com:amr": "unauthenticated"
220
- }
221
- }
248
+ },
249
+ },
222
250
  ),
223
251
  inline_policies={
224
252
  "RUMPolicy": iam.PolicyDocument(
225
253
  statements=[
226
254
  iam.PolicyStatement(
227
255
  effect=iam.Effect.ALLOW,
228
- actions=[
229
- "rum:PutRumEvents"
256
+ actions=["rum:PutRumEvents"],
257
+ resources=[
258
+ f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"
230
259
  ],
231
- resources=[f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"]
232
260
  )
233
261
  ]
234
262
  )
235
- }
263
+ },
236
264
  )
237
265
 
238
266
  # Attach the role to the identity pool
239
267
  cognito.CfnIdentityPoolRoleAttachment(
240
268
  self,
241
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-role-attachment"),
269
+ id=_resource_name("minimal-role-attachment"),
242
270
  identity_pool_id=self.identity_pool.ref,
243
- roles={
244
- "unauthenticated": guest_role.role_arn
245
- }
271
+ roles={"unauthenticated": guest_role.role_arn},
246
272
  )
247
273
 
248
274
  return self.identity_pool.ref, guest_role.role_arn
249
275
 
250
- def _create_app_monitor(self, identity_pool_id: str, guest_role_arn: Optional[str]) -> None:
276
+ def _create_app_monitor(
277
+ self, identity_pool_id: str, guest_role_arn: Optional[str]
278
+ ) -> None:
251
279
  """Create the CloudWatch RUM app monitor"""
252
- logger.info(f"Creating RUM app monitor: {self.rum_config.name}")
280
+ logger.info("Creating CloudWatch RUM app monitor")
281
+
282
+ def _resource_name(name: str) -> str:
283
+ """Helper to generate resource names"""
284
+ return f"{self.rum_config.name}-{name}"
253
285
 
254
- # Build app monitor configuration
286
+ # Create app monitor configuration
255
287
  app_monitor_config = rum.CfnAppMonitor.AppMonitorConfigurationProperty(
256
- identity_pool_id=identity_pool_id,
257
- guest_role_arn=guest_role_arn,
258
288
  allow_cookies=self.rum_config.allow_cookies,
259
289
  enable_x_ray=self.rum_config.enable_xray,
290
+ favorite_pages=self.rum_config.favorite_pages,
291
+ guest_role_arn=guest_role_arn,
292
+ identity_pool_id=identity_pool_id,
260
293
  session_sample_rate=self.rum_config.session_sample_rate,
261
- telemetries=self.rum_config.telemetries
294
+ telemetries=self.rum_config.telemetries,
262
295
  )
263
296
 
264
- # Add optional properties
265
- if self.rum_config.excluded_pages:
266
- app_monitor_config.excluded_pages = self.rum_config.excluded_pages
267
-
268
- if self.rum_config.included_pages:
269
- app_monitor_config.included_pages = self.rum_config.included_pages
270
-
271
- if self.rum_config.favorite_pages:
272
- app_monitor_config.favorite_pages = self.rum_config.favorite_pages
273
-
274
- if self.rum_config.metric_destinations:
275
- app_monitor_config.metric_destinations = [
276
- rum.CfnAppMonitor.MetricDestinationProperty(**dest)
277
- for dest in self.rum_config.metric_destinations
278
- ]
279
-
280
- # Create custom events configuration if enabled
281
- custom_events = None
282
- if self.rum_config.custom_events_enabled:
283
- custom_events = rum.CfnAppMonitor.CustomEventsProperty(
284
- status="ENABLED"
285
- )
286
-
287
- # Create the app monitor
288
297
  self.app_monitor = rum.CfnAppMonitor(
289
298
  self,
290
- id=self.deployment.build_resource_name(f"{self.rum_config.name}-app-monitor"),
299
+ id=_resource_name("app-monitor"),
291
300
  name=self.rum_config.name,
292
- app_monitor_configuration=app_monitor_config,
293
301
  domain=self.rum_config.domain,
294
- domain_list=self.rum_config.domain_list,
302
+ app_monitor_configuration=app_monitor_config,
295
303
  cw_log_enabled=self.rum_config.cw_log_enabled,
296
- custom_events=custom_events
297
304
  )
298
305
 
306
+ logger.info(f"Created CloudWatch RUM app monitor: {self.rum_config.name}")
307
+
308
+ # Create custom events configuration if enabled
309
+ custom_events = None
310
+ if self.rum_config.custom_events_enabled:
311
+ custom_events = rum.CfnAppMonitor.CustomEventsProperty(status="ENABLED")
312
+
313
+ # Update the app monitor with additional properties
314
+ # (Note: some properties like custom_events need to be set during creation)
315
+
299
316
  # Add tags if specified
300
317
  if self.rum_config.tags:
301
318
  for key, value in self.rum_config.tags.items():
@@ -324,8 +341,8 @@ class RumStack(IStack, EnhancedSsmParameterMixin):
324
341
  resource_values["user_pool_id"] = self.user_pool.user_pool_id
325
342
 
326
343
  # Use enhanced SSM parameter export
327
- exported_params = self.auto_export_resources(resource_values)
328
-
344
+ exported_params = self.export_ssm_parameters(resource_values)
345
+
329
346
  if exported_params:
330
347
  logger.info(f"Exported {len(exported_params)} RUM parameters to SSM")
331
348
  else:
@@ -11,6 +11,7 @@ from cdk_factory.configurations.resources.security_group_full_stack import (
11
11
  SecurityGroupFullStackConfig,
12
12
  )
13
13
  from cdk_factory.interfaces.istack import IStack
14
+ from cdk_factory.interfaces.vpc_provider_mixin import VPCProviderMixin
14
15
  from cdk_factory.stack.stack_module_registry import register_stack
15
16
  from cdk_factory.workload.workload_factory import WorkloadConfig
16
17
 
@@ -19,7 +20,7 @@ logger = Logger(service="SecurityGroupFullStack")
19
20
 
20
21
  @register_stack("security_group_full_stack_library_module")
21
22
  @register_stack("security_group_full_stack")
22
- class SecurityGroupsStack(IStack):
23
+ class SecurityGroupsStack(IStack, VPCProviderMixin):
23
24
 
24
25
  def __init__(self, scope: Construct, id: str, **kwargs) -> None:
25
26
  super().__init__(scope, id, **kwargs)
@@ -193,37 +194,7 @@ class SecurityGroupsStack(IStack):
193
194
  description="Uptime Robot",
194
195
  )
195
196
 
196
- # =========================================================
197
- # Outputs (exports)
198
- # =========================================================
199
- cdk.CfnOutput(
200
- self,
201
- "WebFleetAlbSecurityGroupOut",
202
- value=alb_sg.ref,
203
- description="Web Fleet Application Load Balancer Security Group",
204
- export_name=f"{self.deployment.environment}-{self.workload.name}-WebFleetAlbSecurityGroup",
205
- )
206
- cdk.CfnOutput(
207
- self,
208
- "WebFleetInstancesSecurityGroupOut",
209
- value=web_fleet_sg.ref,
210
- description="Web Fleet Instances Security Group",
211
- export_name=f"{self.deployment.environment}-{self.workload.name}-WebFleetInstancesSecurityGroup",
212
- )
213
- cdk.CfnOutput(
214
- self,
215
- "MySqlDbSecurityGroupOut",
216
- value=mysql_sg.ref,
217
- description="MySql Security Group",
218
- export_name=f"{self.deployment.environment}-{self.workload.name}-MySqlDbSecurityGroup",
219
- )
220
- cdk.CfnOutput(
221
- self,
222
- "WebMonitoringSecurityGroupOut",
223
- value=monitoring_sg.ref,
224
- description="Web Fleet Application Load Balancer Security Group",
225
- export_name=f"{self.deployment.environment}-{self.workload.name}-WebMonitoringSecurityGroup",
226
- )
197
+
227
198
 
228
199
  # =========================================================
229
200
  # SSM Parameter Store Exports
@@ -274,30 +245,16 @@ class SecurityGroupsStack(IStack):
274
245
 
275
246
  @property
276
247
  def vpc(self) -> ec2.IVpc:
277
- """Get the VPC for the Security Group"""
248
+ """Get the VPC for the Security Group using centralized VPC provider mixin."""
278
249
  if self._vpc:
279
250
  return self._vpc
280
251
 
281
- # Check SSM imported values first (tokens from SSM parameters)
282
- if "vpc_id" in self.ssm_imported_values:
283
- vpc_id = self.ssm_imported_values["vpc_id"]
284
-
285
- # Build VPC attributes
286
- vpc_attrs = {
287
- "vpc_id": vpc_id,
288
- "availability_zones": ["us-east-1a", "us-east-1b"]
289
- }
290
-
291
- # Use from_vpc_attributes() instead of from_lookup() because SSM imports return tokens
292
- # from_lookup() requires concrete values and queries AWS during synthesis
293
- self._vpc = ec2.Vpc.from_vpc_attributes(self, "VPC", **vpc_attrs)
294
- elif self.sg_config.vpc_id:
295
- self._vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=self.sg_config.vpc_id)
296
- elif self.workload.vpc_id:
297
- self._vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=self.workload.vpc_id)
298
- else:
299
- raise ValueError("VPC ID is not defined in the configuration or SSM imports.")
300
-
252
+ # Use the centralized VPC resolution from VPCProviderMixin
253
+ self._vpc = self.resolve_vpc(
254
+ config=self.sg_config,
255
+ deployment=self.deployment,
256
+ workload=self.workload
257
+ )
301
258
  return self._vpc
302
259
 
303
260
  def _export_ssm_parameters(self, security_groups_map: Dict[str, ec2.CfnSecurityGroup]) -> None:
@@ -15,7 +15,8 @@ from cdk_factory.configurations.deployment import DeploymentConfig
15
15
  from cdk_factory.configurations.stack import StackConfig
16
16
  from cdk_factory.configurations.resources.security_group import SecurityGroupConfig
17
17
  from cdk_factory.interfaces.istack import IStack
18
- from cdk_factory.interfaces.enhanced_ssm_parameter_mixin import EnhancedSsmParameterMixin
18
+ from cdk_factory.interfaces.vpc_provider_mixin import VPCProviderMixin
19
+ from cdk_factory.interfaces.standardized_ssm_mixin import StandardizedSsmMixin
19
20
  from cdk_factory.stack.stack_module_registry import register_stack
20
21
  from cdk_factory.workload.workload_factory import WorkloadConfig
21
22
 
@@ -24,7 +25,7 @@ logger = Logger(service="SecurityGroupStack")
24
25
 
25
26
  @register_stack("security_group_library_module")
26
27
  @register_stack("security_group_stack")
27
- class SecurityGroupStack(IStack, EnhancedSsmParameterMixin):
28
+ class SecurityGroupStack(IStack, VPCProviderMixin, StandardizedSsmMixin):
28
29
  """
29
30
  Reusable stack for AWS Security Groups.
30
31
  Supports creating security groups with customizable rules.
@@ -82,17 +83,16 @@ class SecurityGroupStack(IStack, EnhancedSsmParameterMixin):
82
83
 
83
84
  @property
84
85
  def vpc(self) -> ec2.IVpc:
85
- """Get the VPC for the Security Group"""
86
+ """Get the VPC for the Security Group using centralized VPC provider mixin."""
86
87
  if self._vpc:
87
88
  return self._vpc
88
- if self.sg_config.vpc_id:
89
- self._vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=self.sg_config.vpc_id)
90
- elif self.workload.vpc_id:
91
- self._vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=self.workload.vpc_id)
92
-
93
- else:
94
- raise ValueError("VPC ID is not defined in the configuration.")
95
-
89
+
90
+ # Use the centralized VPC resolution from VPCProviderMixin
91
+ self._vpc = self.resolve_vpc(
92
+ config=self.sg_config,
93
+ deployment=self.deployment,
94
+ workload=self.workload
95
+ )
96
96
  return self._vpc
97
97
 
98
98
  def _create_security_group(self, sg_name: str) -> ec2.SecurityGroup:
@@ -337,14 +337,7 @@ class SecurityGroupStack(IStack, EnhancedSsmParameterMixin):
337
337
 
338
338
  def _export_cfn_outputs(self, sg_name: str) -> None:
339
339
  """Add CloudFormation outputs for the Security Group"""
340
- if self.security_group:
341
- # Security Group ID
342
- cdk.CfnOutput(
343
- self,
344
- f"{sg_name}-id",
345
- value=self.security_group.security_group_id,
346
- export_name=f"{self.deployment.build_resource_name(sg_name)}-id",
347
- )
340
+ return
348
341
 
349
342
  def _export_ssm_parameters(self, sg_name: str) -> None:
350
343
  """Add SSM parameters for the Security Group"""
@@ -131,37 +131,4 @@ class SQSStack(IStack):
131
131
 
132
132
  def _add_outputs(self) -> None:
133
133
  """Add CloudFormation outputs for the SQS queues"""
134
- for queue_name, queue in self.queues.items():
135
- # Queue ARN
136
- cdk.CfnOutput(
137
- self,
138
- f"{queue_name}-arn",
139
- value=queue.queue_arn,
140
- export_name=f"{self.deployment.build_resource_name(queue_name)}-arn"
141
- )
142
-
143
- # Queue URL
144
- cdk.CfnOutput(
145
- self,
146
- f"{queue_name}-url",
147
- value=queue.queue_url,
148
- export_name=f"{self.deployment.build_resource_name(queue_name)}-url"
149
- )
150
-
151
- # Also add outputs for DLQs
152
- for dlq_name, dlq in self.dead_letter_queues.items():
153
- # DLQ ARN
154
- cdk.CfnOutput(
155
- self,
156
- f"{dlq_name}-arn",
157
- value=dlq.queue_arn,
158
- export_name=f"{self.deployment.build_resource_name(dlq_name)}-arn"
159
- )
160
-
161
- # DLQ URL
162
- cdk.CfnOutput(
163
- self,
164
- f"{dlq_name}-url",
165
- value=dlq.queue_url,
166
- export_name=f"{self.deployment.build_resource_name(dlq_name)}-url"
167
- )
134
+ return
@@ -54,6 +54,11 @@ class StackStandards:
54
54
  git_hash = GitUtilities.get_git_commit_hash()
55
55
  if git_hash:
56
56
  aws_cdk.Tags.of(scope).add("ApplicationGitHash", git_hash)
57
+
58
+ # Add CDK Factory version for tracking and debugging
59
+ from cdk_factory.version import __version__
60
+ aws_cdk.Tags.of(scope).add("CdkFactoryVersion", __version__)
61
+
57
62
  aws_cdk.Tags.of(scope).add(
58
63
  "DeploymentDateUTC", str(datetime.datetime.now(datetime.UTC))
59
64
  )