terraformgraph 1.0.1__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.
@@ -0,0 +1,19 @@
1
+ """terraformgraph - Create architecture diagrams from Terraform configurations."""
2
+
3
+ __version__ = "1.0.1"
4
+
5
+ from .aggregator import ResourceAggregator
6
+ from .config_loader import ConfigLoader
7
+ from .layout import LayoutEngine
8
+ from .parser import TerraformParser
9
+ from .renderer import HTMLRenderer, SVGRenderer
10
+
11
+ __all__ = [
12
+ "__version__",
13
+ "TerraformParser",
14
+ "ResourceAggregator",
15
+ "LayoutEngine",
16
+ "SVGRenderer",
17
+ "HTMLRenderer",
18
+ "ConfigLoader",
19
+ ]
@@ -0,0 +1,6 @@
1
+ """Entry point for running as a module: python -m terraform_diagram"""
2
+
3
+ from .main import main
4
+
5
+ if __name__ == '__main__':
6
+ main()
@@ -0,0 +1,396 @@
1
+ """
2
+ Resource Aggregator
3
+
4
+ Aggregates low-level Terraform resources into high-level logical services
5
+ for cleaner architecture diagrams.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from .config_loader import ConfigLoader
12
+ from .parser import ParseResult, TerraformResource
13
+
14
+
15
+ @dataclass
16
+ class LogicalService:
17
+ """A high-level logical service aggregating multiple resources."""
18
+ service_type: str # e.g., 'alb', 'ecs', 's3', 'sqs'
19
+ name: str
20
+ icon_resource_type: str # The Terraform type to use for the icon
21
+ resources: List[TerraformResource] = field(default_factory=list)
22
+ count: int = 1 # How many instances (e.g., 24 SQS queues)
23
+ is_vpc_resource: bool = False
24
+ attributes: Dict[str, str] = field(default_factory=dict)
25
+
26
+ @property
27
+ def id(self) -> str:
28
+ return f"{self.service_type}.{self.name}"
29
+
30
+
31
+ @dataclass
32
+ class LogicalConnection:
33
+ """A connection between logical services."""
34
+ source_id: str
35
+ target_id: str
36
+ label: Optional[str] = None
37
+ connection_type: str = 'default' # 'default', 'data_flow', 'trigger', 'encrypt'
38
+
39
+
40
+ @dataclass
41
+ class AggregatedResult:
42
+ """Result of aggregating resources into logical services."""
43
+ services: List[LogicalService] = field(default_factory=list)
44
+ connections: List[LogicalConnection] = field(default_factory=list)
45
+ vpc_services: List[LogicalService] = field(default_factory=list)
46
+ global_services: List[LogicalService] = field(default_factory=list)
47
+
48
+
49
+ # Define which resource types should be aggregated together
50
+ AGGREGATION_RULES = {
51
+ # Load Balancing: ALB + listeners + target groups = one ALB
52
+ 'alb': {
53
+ 'primary': ['aws_lb'],
54
+ 'aggregate': ['aws_lb_listener', 'aws_lb_target_group', 'aws_lb_target_group_attachment'],
55
+ 'icon': 'aws_lb',
56
+ 'display_name': 'Load Balancer',
57
+ 'is_vpc': True,
58
+ },
59
+ # ECS: cluster + services + task definitions = one ECS
60
+ 'ecs': {
61
+ 'primary': ['aws_ecs_cluster'],
62
+ 'aggregate': ['aws_ecs_service', 'aws_ecs_task_definition'],
63
+ 'icon': 'aws_ecs_cluster',
64
+ 'display_name': 'ECS Cluster',
65
+ 'is_vpc': True,
66
+ },
67
+ # VPC: vpc + subnets + gateways + route tables = one VPC
68
+ 'vpc': {
69
+ 'primary': ['aws_vpc'],
70
+ 'aggregate': ['aws_subnet', 'aws_internet_gateway', 'aws_nat_gateway',
71
+ 'aws_route_table', 'aws_route', 'aws_route_table_association',
72
+ 'aws_eip', 'aws_vpc_endpoint', 'aws_db_subnet_group'],
73
+ 'icon': 'aws_vpc',
74
+ 'display_name': 'VPC',
75
+ 'is_vpc': True,
76
+ },
77
+ # Security Groups: aggregate all SGs
78
+ 'security': {
79
+ 'primary': ['aws_security_group'],
80
+ 'aggregate': ['aws_security_group_rule'],
81
+ 'icon': 'aws_security_group',
82
+ 'display_name': 'Security Groups',
83
+ 'is_vpc': True,
84
+ },
85
+ # S3: buckets (aggregate policies, versioning, etc.)
86
+ 's3': {
87
+ 'primary': ['aws_s3_bucket'],
88
+ 'aggregate': ['aws_s3_bucket_policy', 'aws_s3_bucket_versioning',
89
+ 'aws_s3_bucket_lifecycle_configuration', 'aws_s3_bucket_notification',
90
+ 'aws_s3_bucket_cors_configuration', 'aws_s3_bucket_public_access_block',
91
+ 'aws_s3_bucket_ownership_controls', 'aws_s3_bucket_server_side_encryption_configuration'],
92
+ 'icon': 'aws_s3_bucket',
93
+ 'display_name': 'S3 Buckets',
94
+ 'is_vpc': False,
95
+ },
96
+ # SQS: aggregate all queues
97
+ 'sqs': {
98
+ 'primary': ['aws_sqs_queue'],
99
+ 'aggregate': ['aws_sqs_queue_policy'],
100
+ 'icon': 'aws_sqs_queue',
101
+ 'display_name': 'SQS Queues',
102
+ 'is_vpc': False,
103
+ },
104
+ # SNS: aggregate topics
105
+ 'sns': {
106
+ 'primary': ['aws_sns_topic'],
107
+ 'aggregate': ['aws_sns_topic_policy', 'aws_sns_topic_subscription'],
108
+ 'icon': 'aws_sns_topic',
109
+ 'display_name': 'SNS Topics',
110
+ 'is_vpc': False,
111
+ },
112
+ # Cognito: user pool + clients + domain
113
+ 'cognito': {
114
+ 'primary': ['aws_cognito_user_pool'],
115
+ 'aggregate': ['aws_cognito_user_pool_client', 'aws_cognito_user_pool_domain',
116
+ 'aws_cognito_identity_pool', 'aws_cognito_identity_pool_roles_attachment',
117
+ 'aws_cognito_log_delivery_configuration'],
118
+ 'icon': 'aws_cognito_user_pool',
119
+ 'display_name': 'Cognito',
120
+ 'is_vpc': False,
121
+ },
122
+ # KMS: keys + aliases
123
+ 'kms': {
124
+ 'primary': ['aws_kms_key'],
125
+ 'aggregate': ['aws_kms_alias'],
126
+ 'icon': 'aws_kms_key',
127
+ 'display_name': 'KMS Keys',
128
+ 'is_vpc': False,
129
+ },
130
+ # Secrets Manager
131
+ 'secrets': {
132
+ 'primary': ['aws_secretsmanager_secret'],
133
+ 'aggregate': ['aws_secretsmanager_secret_version'],
134
+ 'icon': 'aws_secretsmanager_secret',
135
+ 'display_name': 'Secrets Manager',
136
+ 'is_vpc': False,
137
+ },
138
+ # Route53
139
+ 'route53': {
140
+ 'primary': ['aws_route53_zone'],
141
+ 'aggregate': ['aws_route53_record'],
142
+ 'icon': 'aws_route53_zone',
143
+ 'display_name': 'Route 53',
144
+ 'is_vpc': False,
145
+ },
146
+ # ACM Certificates
147
+ 'acm': {
148
+ 'primary': ['aws_acm_certificate'],
149
+ 'aggregate': ['aws_acm_certificate_validation'],
150
+ 'icon': 'aws_acm_certificate',
151
+ 'display_name': 'Certificates',
152
+ 'is_vpc': False,
153
+ },
154
+ # CloudWatch
155
+ 'cloudwatch': {
156
+ 'primary': ['aws_cloudwatch_log_group', 'aws_cloudwatch_metric_alarm'],
157
+ 'aggregate': ['aws_cloudwatch_log_resource_policy', 'aws_cloudwatch_log_delivery',
158
+ 'aws_cloudwatch_log_delivery_source', 'aws_cloudwatch_log_delivery_destination',
159
+ 'aws_cloudwatch_dashboard'],
160
+ 'icon': 'aws_cloudwatch_metric_alarm',
161
+ 'display_name': 'CloudWatch',
162
+ 'is_vpc': False,
163
+ },
164
+ # EventBridge
165
+ 'eventbridge': {
166
+ 'primary': ['aws_cloudwatch_event_rule', 'aws_cloudwatch_event_bus'],
167
+ 'aggregate': ['aws_cloudwatch_event_target', 'aws_cloudwatch_event_archive'],
168
+ 'icon': 'aws_cloudwatch_event_rule',
169
+ 'display_name': 'EventBridge',
170
+ 'is_vpc': False,
171
+ },
172
+ # WAF
173
+ 'waf': {
174
+ 'primary': ['aws_wafv2_web_acl'],
175
+ 'aggregate': ['aws_wafv2_web_acl_association', 'aws_wafv2_rule_group'],
176
+ 'icon': 'aws_wafv2_web_acl',
177
+ 'display_name': 'WAF',
178
+ 'is_vpc': False,
179
+ },
180
+ # IAM
181
+ 'iam': {
182
+ 'primary': ['aws_iam_role'],
183
+ 'aggregate': ['aws_iam_policy', 'aws_iam_role_policy', 'aws_iam_role_policy_attachment',
184
+ 'aws_iam_instance_profile'],
185
+ 'icon': 'aws_iam_role',
186
+ 'display_name': 'IAM Roles',
187
+ 'is_vpc': False,
188
+ },
189
+ # ECR
190
+ 'ecr': {
191
+ 'primary': ['aws_ecr_repository'],
192
+ 'aggregate': [],
193
+ 'icon': 'aws_ecr_repository',
194
+ 'display_name': 'ECR',
195
+ 'is_vpc': False,
196
+ },
197
+ # DynamoDB
198
+ 'dynamodb': {
199
+ 'primary': ['aws_dynamodb_table'],
200
+ 'aggregate': [],
201
+ 'icon': 'aws_dynamodb_table',
202
+ 'display_name': 'DynamoDB',
203
+ 'is_vpc': False,
204
+ },
205
+ # SES
206
+ 'ses': {
207
+ 'primary': ['aws_ses_domain_identity'],
208
+ 'aggregate': ['aws_ses_domain_dkim', 'aws_ses_domain_mail_from',
209
+ 'aws_ses_identity_notification_topic', 'aws_ses_configuration_set'],
210
+ 'icon': 'aws_ses_domain_identity',
211
+ 'display_name': 'SES',
212
+ 'is_vpc': False,
213
+ },
214
+ # CloudFront
215
+ 'cloudfront': {
216
+ 'primary': ['aws_cloudfront_distribution'],
217
+ 'aggregate': ['aws_cloudfront_origin_access_control'],
218
+ 'icon': 'aws_cloudfront_distribution',
219
+ 'display_name': 'CloudFront',
220
+ 'is_vpc': False,
221
+ },
222
+ # Bedrock
223
+ 'bedrock': {
224
+ 'primary': ['aws_bedrockagent_knowledge_base'],
225
+ 'aggregate': [],
226
+ 'icon': 'aws_bedrockagent_knowledge_base',
227
+ 'display_name': 'Bedrock KB',
228
+ 'is_vpc': False,
229
+ },
230
+ # Budgets
231
+ 'budgets': {
232
+ 'primary': ['aws_budgets_budget'],
233
+ 'aggregate': [],
234
+ 'icon': 'aws_budgets_budget',
235
+ 'display_name': 'Budgets',
236
+ 'is_vpc': False,
237
+ },
238
+ # EC2 (standalone instances like DevOps agent)
239
+ 'ec2': {
240
+ 'primary': ['aws_instance'],
241
+ 'aggregate': ['aws_launch_template'],
242
+ 'icon': 'aws_instance',
243
+ 'display_name': 'EC2',
244
+ 'is_vpc': True,
245
+ },
246
+ # MongoDB Atlas (external)
247
+ 'mongodb': {
248
+ 'primary': ['mongodbatlas_cluster'],
249
+ 'aggregate': ['mongodbatlas_network_peering', 'mongodbatlas_project_ip_access_list'],
250
+ 'icon': 'aws_dynamodb_table', # Use DynamoDB icon as fallback
251
+ 'display_name': 'MongoDB Atlas',
252
+ 'is_vpc': False,
253
+ },
254
+ }
255
+
256
+ # High-level connections between service types
257
+ LOGICAL_CONNECTIONS = [
258
+ # Internet -> WAF -> CloudFront -> ALB
259
+ ('cloudfront', 'alb', 'HTTPS', 'data_flow'),
260
+ ('waf', 'alb', 'protects', 'default'),
261
+ ('waf', 'cognito', 'protects', 'default'),
262
+
263
+ # ALB -> ECS
264
+ ('alb', 'ecs', 'routes to', 'data_flow'),
265
+
266
+ # ECS -> various services
267
+ ('ecs', 'sqs', 'sends/receives', 'data_flow'),
268
+ ('ecs', 's3', 'reads/writes', 'data_flow'),
269
+ ('ecs', 'dynamodb', 'queries', 'data_flow'),
270
+ ('ecs', 'secrets', 'reads', 'default'),
271
+ ('ecs', 'bedrock', 'invokes', 'data_flow'),
272
+
273
+ # S3 -> SQS (notifications)
274
+ ('s3', 'sqs', 'triggers', 'trigger'),
275
+
276
+ # SNS for alerts
277
+ ('cloudwatch', 'sns', 'alerts', 'trigger'),
278
+ ('sqs', 'sns', 'DLQ alerts', 'trigger'),
279
+
280
+ # Encryption
281
+ ('kms', 's3', 'encrypts', 'encrypt'),
282
+ ('kms', 'sqs', 'encrypts', 'encrypt'),
283
+ ('kms', 'sns', 'encrypts', 'encrypt'),
284
+ ('kms', 'secrets', 'encrypts', 'encrypt'),
285
+
286
+ # DNS
287
+ ('route53', 'alb', 'resolves', 'default'),
288
+ ('route53', 'cloudfront', 'resolves', 'default'),
289
+
290
+ # Certificates
291
+ ('acm', 'alb', 'TLS', 'default'),
292
+ ('acm', 'cloudfront', 'TLS', 'default'),
293
+
294
+ # Cognito auth
295
+ ('cognito', 'alb', 'authenticates', 'default'),
296
+
297
+ # ECR -> ECS
298
+ ('ecr', 'ecs', 'images', 'data_flow'),
299
+
300
+ # External
301
+ ('ecs', 'mongodb', 'queries', 'data_flow'),
302
+ ]
303
+
304
+
305
+ class ResourceAggregator:
306
+ """Aggregates Terraform resources into logical services."""
307
+
308
+ def __init__(self, config_loader: Optional[ConfigLoader] = None):
309
+ self._config = config_loader or ConfigLoader()
310
+ self._aggregation_rules = self._build_aggregation_rules()
311
+ self._logical_connections = self._config.get_logical_connections()
312
+ self._build_type_to_rule_map()
313
+
314
+ def _build_aggregation_rules(self) -> Dict[str, Dict[str, Any]]:
315
+ """Build aggregation rules dict from config."""
316
+ flat_rules = self._config.get_flat_aggregation_rules()
317
+ result = {}
318
+ for service_name, config in flat_rules.items():
319
+ # Map YAML format (primary/secondary/in_vpc) to internal format
320
+ result[service_name] = {
321
+ 'primary': config.get("primary", []),
322
+ 'aggregate': config.get("secondary", []), # secondary in YAML -> aggregate internally
323
+ 'icon': config.get("primary", [""])[0] if config.get("primary") else "",
324
+ 'display_name': service_name.replace("_", " ").title(),
325
+ 'is_vpc': config.get("in_vpc", False),
326
+ }
327
+ return result
328
+
329
+ def _build_type_to_rule_map(self) -> None:
330
+ """Build a mapping from resource type to aggregation rule."""
331
+ self._type_to_rule: Dict[str, str] = {}
332
+ for rule_name, rule in self._aggregation_rules.items():
333
+ for res_type in rule['primary']:
334
+ self._type_to_rule[res_type] = rule_name
335
+ for res_type in rule['aggregate']:
336
+ self._type_to_rule[res_type] = rule_name
337
+
338
+ def aggregate(self, parse_result: ParseResult) -> AggregatedResult:
339
+ """Aggregate parsed resources into logical services."""
340
+ result = AggregatedResult()
341
+
342
+ # Group resources by aggregation rule
343
+ rule_resources: Dict[str, List[TerraformResource]] = {}
344
+ unmatched: List[TerraformResource] = []
345
+
346
+ for resource in parse_result.resources:
347
+ rule_name = self._type_to_rule.get(resource.resource_type)
348
+ if rule_name:
349
+ rule_resources.setdefault(rule_name, []).append(resource)
350
+ else:
351
+ unmatched.append(resource)
352
+
353
+ # Create logical services from grouped resources
354
+ for rule_name, resources in rule_resources.items():
355
+ rule = self._aggregation_rules[rule_name]
356
+
357
+ # Count primary resources
358
+ primary_count = sum(1 for r in resources if r.resource_type in rule['primary'])
359
+ if primary_count == 0:
360
+ continue # Skip if no primary resources
361
+
362
+ service = LogicalService(
363
+ service_type=rule_name,
364
+ name=rule['display_name'],
365
+ icon_resource_type=rule['icon'],
366
+ resources=resources,
367
+ count=primary_count,
368
+ is_vpc_resource=rule['is_vpc'],
369
+ )
370
+
371
+ result.services.append(service)
372
+ if service.is_vpc_resource:
373
+ result.vpc_services.append(service)
374
+ else:
375
+ result.global_services.append(service)
376
+
377
+ # Create logical connections based on which services exist
378
+ existing_services = {s.service_type for s in result.services}
379
+ for conn in self._logical_connections:
380
+ source = conn.get("source", "")
381
+ target = conn.get("target", "")
382
+ if source in existing_services and target in existing_services:
383
+ result.connections.append(LogicalConnection(
384
+ source_id=f"{source}.{self._aggregation_rules[source]['display_name']}",
385
+ target_id=f"{target}.{self._aggregation_rules[target]['display_name']}",
386
+ label=conn.get("label", ""),
387
+ connection_type=conn.get("type", "default"),
388
+ ))
389
+
390
+ return result
391
+
392
+
393
+ def aggregate_resources(parse_result: ParseResult) -> AggregatedResult:
394
+ """Convenience function to aggregate resources."""
395
+ aggregator = ResourceAggregator()
396
+ return aggregator.aggregate(parse_result)
@@ -0,0 +1,132 @@
1
+ # Aggregation rules for grouping Terraform resources into logical services
2
+ # Format: service_name -> list of resource patterns
3
+
4
+ compute:
5
+ ecs:
6
+ primary: ["aws_ecs_cluster", "aws_ecs_service", "aws_ecs_task_definition"]
7
+ secondary: ["aws_ecs_capacity_provider", "aws_appautoscaling_target", "aws_appautoscaling_policy"]
8
+ in_vpc: true
9
+
10
+ ec2:
11
+ primary: ["aws_instance", "aws_launch_template", "aws_autoscaling_group"]
12
+ secondary: ["aws_ami", "aws_ebs_volume"]
13
+ in_vpc: true
14
+
15
+ networking:
16
+ alb:
17
+ primary: ["aws_lb", "aws_alb"]
18
+ secondary: ["aws_lb_listener", "aws_lb_target_group", "aws_alb_listener", "aws_alb_target_group"]
19
+ in_vpc: true
20
+
21
+ vpc:
22
+ primary: ["aws_vpc"]
23
+ secondary: ["aws_subnet", "aws_route_table", "aws_internet_gateway", "aws_nat_gateway", "aws_route_table_association", "aws_eip"]
24
+ in_vpc: true
25
+
26
+ security_groups:
27
+ primary: ["aws_security_group"]
28
+ secondary: ["aws_security_group_rule", "aws_vpc_security_group_ingress_rule", "aws_vpc_security_group_egress_rule"]
29
+ in_vpc: true
30
+
31
+ storage:
32
+ s3:
33
+ primary: ["aws_s3_bucket"]
34
+ secondary: ["aws_s3_bucket_policy", "aws_s3_bucket_versioning", "aws_s3_bucket_lifecycle_configuration", "aws_s3_bucket_public_access_block", "aws_s3_bucket_server_side_encryption_configuration", "aws_s3_bucket_cors_configuration", "aws_s3_bucket_notification", "aws_s3_object"]
35
+ in_vpc: false
36
+
37
+ database:
38
+ dynamodb:
39
+ primary: ["aws_dynamodb_table"]
40
+ secondary: ["aws_dynamodb_table_item", "aws_dynamodb_global_table"]
41
+ in_vpc: false
42
+
43
+ rds:
44
+ primary: ["aws_db_instance", "aws_rds_cluster"]
45
+ secondary: ["aws_db_subnet_group", "aws_db_parameter_group", "aws_rds_cluster_instance"]
46
+ in_vpc: true
47
+
48
+ elasticache:
49
+ primary: ["aws_elasticache_cluster", "aws_elasticache_replication_group"]
50
+ secondary: ["aws_elasticache_subnet_group", "aws_elasticache_parameter_group"]
51
+ in_vpc: true
52
+
53
+ messaging:
54
+ sqs:
55
+ primary: ["aws_sqs_queue"]
56
+ secondary: ["aws_sqs_queue_policy"]
57
+ in_vpc: false
58
+
59
+ sns:
60
+ primary: ["aws_sns_topic"]
61
+ secondary: ["aws_sns_topic_subscription", "aws_sns_topic_policy"]
62
+ in_vpc: false
63
+
64
+ eventbridge:
65
+ primary: ["aws_cloudwatch_event_rule", "aws_cloudwatch_event_bus"]
66
+ secondary: ["aws_cloudwatch_event_target"]
67
+ in_vpc: false
68
+
69
+ security:
70
+ kms:
71
+ primary: ["aws_kms_key"]
72
+ secondary: ["aws_kms_alias"]
73
+ in_vpc: false
74
+
75
+ secrets_manager:
76
+ primary: ["aws_secretsmanager_secret"]
77
+ secondary: ["aws_secretsmanager_secret_version"]
78
+ in_vpc: false
79
+
80
+ iam:
81
+ primary: ["aws_iam_role"]
82
+ secondary: ["aws_iam_policy", "aws_iam_role_policy", "aws_iam_role_policy_attachment", "aws_iam_policy_attachment", "aws_iam_instance_profile"]
83
+ in_vpc: false
84
+
85
+ edge:
86
+ cloudfront:
87
+ primary: ["aws_cloudfront_distribution"]
88
+ secondary: ["aws_cloudfront_origin_access_identity", "aws_cloudfront_origin_access_control", "aws_cloudfront_cache_policy", "aws_cloudfront_response_headers_policy"]
89
+ in_vpc: false
90
+
91
+ waf:
92
+ primary: ["aws_wafv2_web_acl"]
93
+ secondary: ["aws_wafv2_web_acl_association", "aws_wafv2_ip_set", "aws_wafv2_rule_group"]
94
+ in_vpc: false
95
+
96
+ route53:
97
+ primary: ["aws_route53_zone"]
98
+ secondary: ["aws_route53_record"]
99
+ in_vpc: false
100
+
101
+ acm:
102
+ primary: ["aws_acm_certificate"]
103
+ secondary: ["aws_acm_certificate_validation"]
104
+ in_vpc: false
105
+
106
+ auth:
107
+ cognito:
108
+ primary: ["aws_cognito_user_pool"]
109
+ secondary: ["aws_cognito_user_pool_client", "aws_cognito_identity_pool", "aws_cognito_user_pool_domain"]
110
+ in_vpc: false
111
+
112
+ monitoring:
113
+ cloudwatch:
114
+ primary: ["aws_cloudwatch_log_group"]
115
+ secondary: ["aws_cloudwatch_log_stream", "aws_cloudwatch_metric_alarm", "aws_cloudwatch_dashboard"]
116
+ in_vpc: false
117
+
118
+ serverless:
119
+ lambda:
120
+ primary: ["aws_lambda_function"]
121
+ secondary: ["aws_lambda_permission", "aws_lambda_event_source_mapping", "aws_lambda_layer_version"]
122
+ in_vpc: false
123
+
124
+ api_gateway:
125
+ primary: ["aws_api_gateway_rest_api", "aws_apigatewayv2_api"]
126
+ secondary: ["aws_api_gateway_resource", "aws_api_gateway_method", "aws_api_gateway_integration", "aws_api_gateway_deployment", "aws_api_gateway_stage", "aws_apigatewayv2_stage", "aws_apigatewayv2_route", "aws_apigatewayv2_integration"]
127
+ in_vpc: false
128
+
129
+ step_functions:
130
+ primary: ["aws_sfn_state_machine"]
131
+ secondary: []
132
+ in_vpc: false