terraback 0.0.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.
- terraback/__init__.py +1 -0
- terraback/cli/__init__.py +0 -0
- terraback/cli/aws/__init__.py +390 -0
- terraback/cli/aws/acm/__init__.py +53 -0
- terraback/cli/aws/acm/certificates.py +117 -0
- terraback/cli/aws/apigateway/__init__.py +27 -0
- terraback/cli/aws/apigateway/rest_apis.py +341 -0
- terraback/cli/aws/autoscaling/__init__.py +107 -0
- terraback/cli/aws/autoscaling/auto_scaling_groups.py +64 -0
- terraback/cli/aws/autoscaling/launch_configurations.py +64 -0
- terraback/cli/aws/autoscaling/scaling_policies.py +91 -0
- terraback/cli/aws/cloudfront/__init__.py +139 -0
- terraback/cli/aws/cloudfront/cache_policies.py +94 -0
- terraback/cli/aws/cloudfront/distributions.py +220 -0
- terraback/cli/aws/cloudfront/origin_access_controls.py +74 -0
- terraback/cli/aws/cloudfront/origin_request_policies.py +84 -0
- terraback/cli/aws/cloudwatch/__init__.py +103 -0
- terraback/cli/aws/cloudwatch/alarms.py +80 -0
- terraback/cli/aws/cloudwatch/dashboards.py +63 -0
- terraback/cli/aws/cloudwatch/log_groups.py +52 -0
- terraback/cli/aws/ec2/__init__.py +121 -0
- terraback/cli/aws/ec2/amis.py +42 -0
- terraback/cli/aws/ec2/instances.py +42 -0
- terraback/cli/aws/ec2/key_pairs.py +31 -0
- terraback/cli/aws/ec2/launch_templates.py +34 -0
- terraback/cli/aws/ec2/network_interfaces.py +34 -0
- terraback/cli/aws/ec2/snapshots.py +31 -0
- terraback/cli/aws/ec2/volumes.py +34 -0
- terraback/cli/aws/ecr/__init__.py +45 -0
- terraback/cli/aws/ecr/repositories.py +95 -0
- terraback/cli/aws/ecs/__init__.py +125 -0
- terraback/cli/aws/ecs/clusters.py +111 -0
- terraback/cli/aws/ecs/services.py +186 -0
- terraback/cli/aws/ecs/task_definitions.py +244 -0
- terraback/cli/aws/efs/__init__.py +116 -0
- terraback/cli/aws/efs/access_points.py +88 -0
- terraback/cli/aws/efs/file_systems.py +90 -0
- terraback/cli/aws/efs/mount_targets.py +65 -0
- terraback/cli/aws/eips/__init__.py +35 -0
- terraback/cli/aws/eips/addresses.py +22 -0
- terraback/cli/aws/elasticache/__init__.py +176 -0
- terraback/cli/aws/elasticache/memcached_clusters.py +117 -0
- terraback/cli/aws/elasticache/parameter_groups.py +99 -0
- terraback/cli/aws/elasticache/redis_clusters.py +114 -0
- terraback/cli/aws/elasticache/replication_groups.py +127 -0
- terraback/cli/aws/elasticache/subnet_groups.py +84 -0
- terraback/cli/aws/elb/__init__.py +36 -0
- terraback/cli/aws/elb/classic_load_balancers.py +37 -0
- terraback/cli/aws/elbv2/__init__.py +234 -0
- terraback/cli/aws/elbv2/classic_load_balancers.py +37 -0
- terraback/cli/aws/elbv2/listener_rules.py +131 -0
- terraback/cli/aws/elbv2/listeners.py +64 -0
- terraback/cli/aws/elbv2/load_balancers.py +77 -0
- terraback/cli/aws/elbv2/ssl_policies.py +118 -0
- terraback/cli/aws/elbv2/target_group_attachments.py +107 -0
- terraback/cli/aws/elbv2/target_groups.py +61 -0
- terraback/cli/aws/elbv2/waf_associations.py +84 -0
- terraback/cli/aws/iam/__init__.py +36 -0
- terraback/cli/aws/iam/policies.py +39 -0
- terraback/cli/aws/iam/roles.py +25 -0
- terraback/cli/aws/lambda_func/__init__.py +60 -0
- terraback/cli/aws/lambda_func/functions.py +60 -0
- terraback/cli/aws/lambda_func/layers.py +108 -0
- terraback/cli/aws/rds/__init__.py +102 -0
- terraback/cli/aws/rds/instances.py +33 -0
- terraback/cli/aws/rds/parameter_groups.py +43 -0
- terraback/cli/aws/rds/subnet_groups.py +33 -0
- terraback/cli/aws/route53/__init__.py +58 -0
- terraback/cli/aws/route53/records.py +73 -0
- terraback/cli/aws/route53/zones.py +34 -0
- terraback/cli/aws/s3/__init__.py +33 -0
- terraback/cli/aws/s3/buckets.py +54 -0
- terraback/cli/aws/secretsmanager/__init__.py +89 -0
- terraback/cli/aws/secretsmanager/secret_versions.py +103 -0
- terraback/cli/aws/secretsmanager/secrets.py +186 -0
- terraback/cli/aws/session.py +35 -0
- terraback/cli/aws/sns/__init__.py +86 -0
- terraback/cli/aws/sns/sqs.py +75 -0
- terraback/cli/aws/sns/subscriptions.py +174 -0
- terraback/cli/aws/sns/topics.py +145 -0
- terraback/cli/aws/sqs/__init__.py +84 -0
- terraback/cli/aws/sqs/dead_letter_queues.py +63 -0
- terraback/cli/aws/sqs/queues.py +166 -0
- terraback/cli/aws/sqs/sqs.py +160 -0
- terraback/cli/aws/ssm/__init__.py +119 -0
- terraback/cli/aws/ssm/documents.py +203 -0
- terraback/cli/aws/ssm/maintenance_windows.py +161 -0
- terraback/cli/aws/ssm/parameters.py +180 -0
- terraback/cli/aws/vpc/__init__.py +201 -0
- terraback/cli/aws/vpc/internet_gateways.py +62 -0
- terraback/cli/aws/vpc/nat_gateways.py +67 -0
- terraback/cli/aws/vpc/route_tables.py +98 -0
- terraback/cli/aws/vpc/security_groups.py +24 -0
- terraback/cli/aws/vpc/subnets.py +21 -0
- terraback/cli/aws/vpc/vpc_endpoints.py +103 -0
- terraback/cli/aws/vpc/vpcs.py +21 -0
- terraback/cli/azure/__init__.py +172 -0
- terraback/cli/azure/compute/__init__.py +91 -0
- terraback/cli/azure/compute/disks.py +221 -0
- terraback/cli/azure/compute/ssh_keys.py +16 -0
- terraback/cli/azure/compute/virtual_machines.py +387 -0
- terraback/cli/azure/loadbalancer/__init__.py +14 -0
- terraback/cli/azure/loadbalancer/load_balancers.py +16 -0
- terraback/cli/azure/network/__init__.py +104 -0
- terraback/cli/azure/network/nsgs.py +214 -0
- terraback/cli/azure/network/subnets.py +210 -0
- terraback/cli/azure/network/vnets.py +198 -0
- terraback/cli/azure/session.py +87 -0
- terraback/cli/azure/storage/__init__.py +107 -0
- terraback/cli/azure/storage/storage_accounts.py +257 -0
- terraback/cli/commands/__init__.py +1 -0
- terraback/cli/commands/analyse.py +126 -0
- terraback/cli/commands/clean.py +49 -0
- terraback/cli/commands/list.py +54 -0
- terraback/cli/gcp/__init__.py +371 -0
- terraback/cli/gcp/compute/__init__.py +41 -0
- terraback/cli/gcp/compute/disks.py +187 -0
- terraback/cli/gcp/compute/images.py +57 -0
- terraback/cli/gcp/compute/instances.py +241 -0
- terraback/cli/gcp/compute/networks.py +138 -0
- terraback/cli/gcp/network/__init__.py +87 -0
- terraback/cli/gcp/network/firewalls.py +172 -0
- terraback/cli/gcp/network/networks.py +138 -0
- terraback/cli/gcp/network/subnets.py +193 -0
- terraback/cli/gcp/session.py +42 -0
- terraback/cli/gcp/storage/__init__.py +56 -0
- terraback/cli/gcp/storage/buckets.py +197 -0
- terraback/cli/main.py +346 -0
- terraback/core/__init__.py +0 -0
- terraback/core/license.py +337 -0
- terraback/templates/aws/caching/elasticache_memcached_cluster.tf.j2 +69 -0
- terraback/templates/aws/caching/elasticache_parameter_group.tf.j2 +27 -0
- terraback/templates/aws/caching/elasticache_redis_cluster.tf.j2 +69 -0
- terraback/templates/aws/caching/elasticache_replication_group.tf.j2 +136 -0
- terraback/templates/aws/caching/elasticache_subnet_group.tf.j2 +24 -0
- terraback/templates/aws/cdn/cloudfront_cache_policy.tf.j2 +77 -0
- terraback/templates/aws/cdn/cloudfront_distribution.tf.j2 +328 -0
- terraback/templates/aws/cdn/cloudfront_origin_access_control.tf.j2 +13 -0
- terraback/templates/aws/cdn/cloudfront_origin_request_policy.tf.j2 +55 -0
- terraback/templates/aws/compute/amis.tf.j2 +15 -0
- terraback/templates/aws/compute/autoscaling_group.tf.j2 +105 -0
- terraback/templates/aws/compute/autoscaling_policy.tf.j2 +78 -0
- terraback/templates/aws/compute/ec2.tf.j2 +54 -0
- terraback/templates/aws/compute/lambda_function.tf.j2 +42 -0
- terraback/templates/aws/compute/launch_configuration.tf.j2 +77 -0
- terraback/templates/aws/compute/launch_template.tf.j2 +80 -0
- terraback/templates/aws/container/ecr_repository.tf.j2 +44 -0
- terraback/templates/aws/container/ecs_cluster.tf.j2 +83 -0
- terraback/templates/aws/container/ecs_service.tf.j2 +157 -0
- terraback/templates/aws/database/rds_instance.tf.j2 +23 -0
- terraback/templates/aws/database/rds_parameter_group.tf.j2 +21 -0
- terraback/templates/aws/database/rds_subnet_group.tf.j2 +18 -0
- terraback/templates/aws/dns/route53_record.tf.j2 +31 -0
- terraback/templates/aws/dns/route53_zone.tf.j2 +6 -0
- terraback/templates/aws/integration/api_gateway_deployment.tf.j2 +21 -0
- terraback/templates/aws/integration/api_gateway_integration.tf.j2 +16 -0
- terraback/templates/aws/integration/api_gateway_method.tf.j2 +9 -0
- terraback/templates/aws/integration/api_gateway_resource.tf.j2 +9 -0
- terraback/templates/aws/integration/api_gateway_rest_api.tf.j2 +82 -0
- terraback/templates/aws/integration/api_gateway_stage.tf.j2 +9 -0
- terraback/templates/aws/integration/lambda_permission.tf.j2 +16 -0
- terraback/templates/aws/management/ssm_document.tf.j2 +39 -0
- terraback/templates/aws/management/ssm_maintenance_window.tf.j2 +112 -0
- terraback/templates/aws/management/ssm_parameter.tf.j2 +47 -0
- terraback/templates/aws/messaging/sns_subscription.tf.j2 +38 -0
- terraback/templates/aws/messaging/sns_topic.tf.j2 +47 -0
- terraback/templates/aws/messaging/sqs_queue.tf.j2 +53 -0
- terraback/templates/aws/monitoring/cloudwatch_alarm.tf.j2 +105 -0
- terraback/templates/aws/monitoring/cloudwatch_dashboard.tf.j2 +7 -0
- terraback/templates/aws/monitoring/cloudwatch_log_group.tf.j2 +19 -0
- terraback/templates/aws/networking/classic_load_balancer.tf.j2 +46 -0
- terraback/templates/aws/networking/eips.tf.j2 +19 -0
- terraback/templates/aws/networking/elbv2_listener.tf.j2 +164 -0
- terraback/templates/aws/networking/elbv2_listener_rule.tf.j2 +181 -0
- terraback/templates/aws/networking/elbv2_load_balancer.tf.j2 +114 -0
- terraback/templates/aws/networking/elbv2_ssl_policy.tf.j2 +36 -0
- terraback/templates/aws/networking/elbv2_target_group.tf.j2 +97 -0
- terraback/templates/aws/networking/elbv2_target_group_attachments.tf.j2 +22 -0
- terraback/templates/aws/networking/internet_gateway.tf.j2 +18 -0
- terraback/templates/aws/networking/nat_gateway.tf.j2 +26 -0
- terraback/templates/aws/networking/network_interfaces.tf.j2 +50 -0
- terraback/templates/aws/networking/route_table.tf.j2 +75 -0
- terraback/templates/aws/networking/security_groups.tf.j2 +44 -0
- terraback/templates/aws/networking/subnets.tf.j2 +21 -0
- terraback/templates/aws/networking/vpc.tf.j2 +14 -0
- terraback/templates/aws/networking/vpc_endpoint.tf.j2 +49 -0
- terraback/templates/aws/networking/wafv2_web_acl_association.tf.j2 +6 -0
- terraback/templates/aws/security/acm_certificate.tf.j2 +89 -0
- terraback/templates/aws/security/iam_policies.tf.j2 +11 -0
- terraback/templates/aws/security/iam_roles.tf.j2 +18 -0
- terraback/templates/aws/security/key_pairs.tf.j2 +16 -0
- terraback/templates/aws/security/secretsmanager_secret.tf.j2 +90 -0
- terraback/templates/aws/security/secretsmanager_secret_version.tf.j2 +23 -0
- terraback/templates/aws/security/ssm_document.tf.j2 +59 -0
- terraback/templates/aws/security/ssm_maintenance_window.tf.j2 +159 -0
- terraback/templates/aws/security/ssm_parameter.tf.j2 +58 -0
- terraback/templates/aws/serverless/lambda_layer_version.tf.j2 +22 -0
- terraback/templates/aws/storage/ebs_snapshot.tf.j2 +34 -0
- terraback/templates/aws/storage/ecs_task_definition.tf.j2 +343 -0
- terraback/templates/aws/storage/efs_access_point.tf.j2 +41 -0
- terraback/templates/aws/storage/efs_file_system.tf.j2 +57 -0
- terraback/templates/aws/storage/efs_mount_target.tf.j2 +22 -0
- terraback/templates/aws/storage/s3_bucket.tf.j2 +29 -0
- terraback/templates/aws/storage/volumes.tf.j2 +32 -0
- terraback/templates/azure/compute/azure_managed_disk.tf.j2 +105 -0
- terraback/templates/azure/compute/azure_virtual_machine.tf.j2 +139 -0
- terraback/templates/azure/compute/virtual_machine.tf.j2 +111 -0
- terraback/templates/azure/network/azure_network_security_group.tf.j2 +73 -0
- terraback/templates/azure/network/azure_subnet.tf.j2 +72 -0
- terraback/templates/azure/network/azure_virtual_network.tf.j2 +44 -0
- terraback/templates/azure/network/vnet_import.json.tf.j2 +0 -0
- terraback/templates/azure/networking/azure_network_security_group.tf.j2 +77 -0
- terraback/templates/azure/networking/azure_subnet.tf.j2 +76 -0
- terraback/templates/azure/storage/azure_storage_account.tf.j2 +120 -0
- terraback/templates/azure/storage/storage_account.tf.j2 +15 -0
- terraback/templates/azure/storage/storage_account_import.json.j2 +12 -0
- terraback/templates/gcp/compute/gcp_disk.tf.j2 +35 -0
- terraback/templates/gcp/gcp_instance.tf.j2 +65 -0
- terraback/templates/gcp/network/gcp_firewall.tf.j2 +68 -0
- terraback/templates/gcp/network/gcp_network.tf.j2 +23 -0
- terraback/templates/gcp/network/gcp_subnet.tf.j2 +46 -0
- terraback/templates/gcp/storage/gcp_bucket.tf.j2 +97 -0
- terraback/terraform_generator/__init__.py +1 -0
- terraback/terraform_generator/imports.py +57 -0
- terraback/terraform_generator/writer.py +192 -0
- terraback/tests/__init__.py +0 -0
- terraback/tests/integration/__init__.py +0 -0
- terraback/tests/integration/test_vpc_scanner.py +74 -0
- terraback/tests/unit/__init__.py +0 -0
- terraback/tests/unit/test_cross_scan_registry.py +102 -0
- terraback/utils/cleanup.py +15 -0
- terraback/utils/cross_scan_registry.py +448 -0
- terraback/utils/importer.py +75 -0
- terraback-0.0.0.dist-info/METADATA +446 -0
- terraback-0.0.0.dist-info/RECORD +239 -0
- terraback-0.0.0.dist-info/WHEEL +5 -0
- terraback-0.0.0.dist-info/entry_points.txt +2 -0
- terraback-0.0.0.dist-info/licenses/LICENSE +120 -0
- terraback-0.0.0.dist-info/top_level.txt +1 -0
terraback/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.0"
|
|
File without changes
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# terraback/cli/main.py
|
|
2
|
+
import typer
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
# Clean provider imports
|
|
7
|
+
from terraback.cli import aws, azure, gcp
|
|
8
|
+
|
|
9
|
+
# Import command modules
|
|
10
|
+
from terraback.cli.commands.clean import app as clean_app
|
|
11
|
+
from terraback.cli.commands.list import app as list_app
|
|
12
|
+
from terraback.cli.commands.analyse import app as analyse_app
|
|
13
|
+
|
|
14
|
+
# Import licensing
|
|
15
|
+
from terraback.core.license import (
|
|
16
|
+
activate_license, get_active_license, get_active_tier, get_license_status,
|
|
17
|
+
require_professional, require_enterprise, check_feature_access, Tier
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
app = typer.Typer(
|
|
21
|
+
name="terraback",
|
|
22
|
+
help="Terraback: A tool to generate Terraform from existing cloud infrastructure.",
|
|
23
|
+
no_args_is_help=True
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# License Command Group
|
|
27
|
+
license_app = typer.Typer(help="Manage your Terraback license.")
|
|
28
|
+
|
|
29
|
+
@license_app.command("status")
|
|
30
|
+
def license_status():
|
|
31
|
+
"""Check the current license status and tier."""
|
|
32
|
+
status = get_license_status()
|
|
33
|
+
|
|
34
|
+
typer.echo(f"Active Feature Tier: {typer.style(status['active_tier'].capitalize(), bold=True)}")
|
|
35
|
+
|
|
36
|
+
if status['has_license']:
|
|
37
|
+
typer.secho("\nLicense Details:", fg=typer.colors.GREEN)
|
|
38
|
+
typer.echo(f" - Email: {status.get('email', 'N/A')}")
|
|
39
|
+
typer.echo(f" - Tier: {status.get('tier', 'N/A').capitalize()}")
|
|
40
|
+
typer.echo(f" - Expires: {status.get('expires', 'N/A')}")
|
|
41
|
+
if status.get('order_id'):
|
|
42
|
+
typer.echo(f" - Order ID: {status.get('order_id')}")
|
|
43
|
+
else:
|
|
44
|
+
typer.secho("\nNo active license key found.", fg=typer.colors.YELLOW)
|
|
45
|
+
typer.echo("Running in Community mode.")
|
|
46
|
+
typer.echo("\nCommunity Edition includes:")
|
|
47
|
+
typer.echo(" Unlimited core resources (EC2, VPC, S3, VMs, VNets, Storage)")
|
|
48
|
+
typer.echo(" Basic dependency mapping")
|
|
49
|
+
typer.echo(" Multi-cloud support (AWS, Azure, GCP)")
|
|
50
|
+
typer.echo(" Community support via GitHub")
|
|
51
|
+
typer.echo("\nTo unlock advanced services (RDS, Lambda, EKS, etc.):")
|
|
52
|
+
typer.echo(" Get Migration Pass: https://terraback.io/pricing")
|
|
53
|
+
typer.echo(" Activate license: terraback license activate <key>")
|
|
54
|
+
|
|
55
|
+
@license_app.command("activate")
|
|
56
|
+
def license_activate(key: str = typer.Argument(..., help="Your license key.")):
|
|
57
|
+
"""Activate a new license key."""
|
|
58
|
+
if activate_license(key):
|
|
59
|
+
typer.secho("License activated successfully!", fg=typer.colors.GREEN, bold=True)
|
|
60
|
+
typer.echo()
|
|
61
|
+
license_status()
|
|
62
|
+
else:
|
|
63
|
+
typer.secho("License activation failed.", fg=typer.colors.RED, bold=True)
|
|
64
|
+
typer.echo("Please check that:")
|
|
65
|
+
typer.echo(" - The license key is copied correctly")
|
|
66
|
+
typer.echo(" - The license hasn't expired")
|
|
67
|
+
typer.echo(" - You have write permissions to ~/.terraback/")
|
|
68
|
+
typer.echo("\nIf you continue to have issues, contact support@terraback.io")
|
|
69
|
+
raise typer.Exit(code=1)
|
|
70
|
+
|
|
71
|
+
@license_app.command("validate")
|
|
72
|
+
def license_validate():
|
|
73
|
+
"""Validate the current license and show detailed information."""
|
|
74
|
+
license_data = get_active_license()
|
|
75
|
+
|
|
76
|
+
if license_data:
|
|
77
|
+
typer.secho("License is valid and active", fg=typer.colors.GREEN, bold=True)
|
|
78
|
+
typer.echo(f"\nLicense Information:")
|
|
79
|
+
typer.echo(f" Email: {license_data.get('email', 'N/A')}")
|
|
80
|
+
typer.echo(f" Tier: {license_data.get('tier', 'N/A').capitalize()}")
|
|
81
|
+
typer.echo(f" Issued: {license_data.get('iat', 'N/A')}")
|
|
82
|
+
typer.echo(f" Expires: {license_data.get('expiry', 'N/A')}")
|
|
83
|
+
|
|
84
|
+
tier = license_data.get('tier', Tier.COMMUNITY)
|
|
85
|
+
if tier == Tier.PROFESSIONAL:
|
|
86
|
+
typer.echo(f"\nProfessional Features Unlocked:")
|
|
87
|
+
typer.echo(f" - Advanced AWS services (RDS, Lambda, EKS, etc.)")
|
|
88
|
+
typer.echo(f" - Dependency scanning with --with-deps")
|
|
89
|
+
typer.echo(f" - Multi-account support")
|
|
90
|
+
typer.echo(f" - Priority email support")
|
|
91
|
+
elif tier == Tier.ENTERPRISE:
|
|
92
|
+
typer.echo(f"\nEnterprise Features Unlocked:")
|
|
93
|
+
typer.echo(f" - All Professional features")
|
|
94
|
+
typer.echo(f" - Custom scanners and integrations")
|
|
95
|
+
typer.echo(f" - SSO integration")
|
|
96
|
+
typer.echo(f" - Dedicated support")
|
|
97
|
+
else:
|
|
98
|
+
typer.secho("No valid license found", fg=typer.colors.RED, bold=True)
|
|
99
|
+
typer.echo("\nRunning in Community mode with core features only.")
|
|
100
|
+
raise typer.Exit(code=1)
|
|
101
|
+
|
|
102
|
+
# Cache Command Group
|
|
103
|
+
cache_app = typer.Typer(help="Manage terraback cache")
|
|
104
|
+
|
|
105
|
+
@cache_app.command("stats")
|
|
106
|
+
def cache_stats():
|
|
107
|
+
"""Show cache statistics."""
|
|
108
|
+
from terraback.utils.scan_cache import get_scan_cache
|
|
109
|
+
|
|
110
|
+
cache = get_scan_cache()
|
|
111
|
+
stats = cache.get_stats()
|
|
112
|
+
|
|
113
|
+
typer.echo("\nCache Statistics:")
|
|
114
|
+
typer.echo(f" Hit Rate: {stats['hit_rate']}")
|
|
115
|
+
typer.echo(f" Total Hits: {stats['hits']}")
|
|
116
|
+
typer.echo(f" Total Misses: {stats['misses']}")
|
|
117
|
+
typer.echo(f" Cache Size: {stats['total_size_kb']} KB")
|
|
118
|
+
typer.echo(f" Memory Cache Items: {stats['memory_cache_size']}")
|
|
119
|
+
typer.echo(f" TTL: {stats['ttl_minutes']:.0f} minutes")
|
|
120
|
+
|
|
121
|
+
@cache_app.command("clear")
|
|
122
|
+
def cache_clear(
|
|
123
|
+
confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation")
|
|
124
|
+
):
|
|
125
|
+
"""Clear all cached data."""
|
|
126
|
+
from terraback.utils.scan_cache import get_scan_cache
|
|
127
|
+
|
|
128
|
+
if not confirm:
|
|
129
|
+
confirm = typer.confirm("Are you sure you want to clear all cached data?")
|
|
130
|
+
|
|
131
|
+
if confirm:
|
|
132
|
+
cache = get_scan_cache()
|
|
133
|
+
cache.clear()
|
|
134
|
+
typer.echo("Cache cleared successfully!")
|
|
135
|
+
else:
|
|
136
|
+
typer.echo("Cache clear cancelled.")
|
|
137
|
+
|
|
138
|
+
@cache_app.command("invalidate")
|
|
139
|
+
def cache_invalidate(
|
|
140
|
+
service: Optional[str] = typer.Option(None, help="Cloud service name (e.g., ec2, s3)"),
|
|
141
|
+
operation: Optional[str] = typer.Option(None, help="Operation name (e.g., describe_instances)")
|
|
142
|
+
):
|
|
143
|
+
"""Invalidate specific cache entries."""
|
|
144
|
+
from terraback.utils.scan_cache import get_scan_cache
|
|
145
|
+
|
|
146
|
+
cache = get_scan_cache()
|
|
147
|
+
count = cache.invalidate_pattern(service, operation)
|
|
148
|
+
|
|
149
|
+
if service and operation:
|
|
150
|
+
typer.echo(f"Invalidated {count} cache entries for {service}:{operation}")
|
|
151
|
+
elif service:
|
|
152
|
+
typer.echo(f"Invalidated {count} cache entries for service: {service}")
|
|
153
|
+
elif operation:
|
|
154
|
+
typer.echo(f"Invalidated {count} cache entries for operation: {operation}")
|
|
155
|
+
else:
|
|
156
|
+
typer.echo(f"Invalidated {count} cache entries")
|
|
157
|
+
|
|
158
|
+
# Add command groups to main app
|
|
159
|
+
app.add_typer(aws.app, name="aws", help="Amazon Web Services resources")
|
|
160
|
+
app.add_typer(azure.app, name="azure", help="Microsoft Azure resources")
|
|
161
|
+
app.add_typer(gcp.app, name="gcp", help="Google Cloud Platform resources")
|
|
162
|
+
app.add_typer(clean_app, name="clean", help="Clean generated files")
|
|
163
|
+
app.add_typer(list_app, name="list", help="List scanned resources")
|
|
164
|
+
app.add_typer(analyse_app, name="analyse", help="Analyse Terraform state")
|
|
165
|
+
app.add_typer(license_app, name="license", help="License management")
|
|
166
|
+
app.add_typer(cache_app, name="cache", help="Cache management")
|
|
167
|
+
|
|
168
|
+
@app.callback()
|
|
169
|
+
def main_callback():
|
|
170
|
+
"""Initialize providers on first command."""
|
|
171
|
+
# Register providers with cross-scan registry
|
|
172
|
+
aws.register()
|
|
173
|
+
azure.register()
|
|
174
|
+
gcp.register()
|
|
175
|
+
|
|
176
|
+
@app.command("scan-all")
|
|
177
|
+
def scan_all(
|
|
178
|
+
provider: str = typer.Argument(..., help="Cloud provider: 'aws', 'azure', or 'gcp'"),
|
|
179
|
+
output_dir: Path = typer.Option("generated", "-o", "--output-dir", help="Directory to save Terraform files"),
|
|
180
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="AWS profile name"),
|
|
181
|
+
region: Optional[str] = typer.Option(None, "--region", "-r", help="AWS region, Azure location, or GCP region"),
|
|
182
|
+
subscription_id: Optional[str] = typer.Option(None, "--subscription-id", "-s", help="Azure subscription ID"),
|
|
183
|
+
project_id: Optional[str] = typer.Option(None, "--project-id", help="GCP project ID"),
|
|
184
|
+
resource_group: Optional[str] = typer.Option(None, "--resource-group", "-g", help="Azure resource group"),
|
|
185
|
+
zone: Optional[str] = typer.Option(None, "--zone", "-z", help="GCP zone"),
|
|
186
|
+
with_deps: bool = typer.Option(False, "--with-deps", help="Recursively scan dependencies (Professional feature)")
|
|
187
|
+
):
|
|
188
|
+
"""Scan all resources for a specific cloud provider."""
|
|
189
|
+
provider = provider.lower()
|
|
190
|
+
|
|
191
|
+
if provider == "aws":
|
|
192
|
+
# Delegate to AWS scan-all
|
|
193
|
+
from terraback.cli.aws import scan_all_aws
|
|
194
|
+
scan_all_aws(
|
|
195
|
+
output_dir=output_dir,
|
|
196
|
+
profile=profile,
|
|
197
|
+
region=region,
|
|
198
|
+
with_deps=with_deps
|
|
199
|
+
)
|
|
200
|
+
elif provider == "azure":
|
|
201
|
+
# Delegate to Azure scan-all
|
|
202
|
+
from terraback.cli.azure import scan_all_azure
|
|
203
|
+
scan_all_azure(
|
|
204
|
+
output_dir=output_dir,
|
|
205
|
+
subscription_id=subscription_id,
|
|
206
|
+
location=region, # region is used as location for Azure
|
|
207
|
+
resource_group_name=resource_group,
|
|
208
|
+
with_deps=with_deps
|
|
209
|
+
)
|
|
210
|
+
elif provider == "gcp":
|
|
211
|
+
# Delegate to GCP scan-all
|
|
212
|
+
from terraback.cli.gcp import scan_all_gcp
|
|
213
|
+
scan_all_gcp(
|
|
214
|
+
output_dir=output_dir,
|
|
215
|
+
project_id=project_id,
|
|
216
|
+
region=region,
|
|
217
|
+
zone=zone,
|
|
218
|
+
with_deps=with_deps
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
typer.echo(f"Error: Unknown provider '{provider}'. Use 'aws', 'azure', or 'gcp'.", err=True)
|
|
222
|
+
raise typer.Exit(code=1)
|
|
223
|
+
|
|
224
|
+
@app.command("scan-recursive")
|
|
225
|
+
@require_professional
|
|
226
|
+
def scan_recursive(
|
|
227
|
+
resource_type: str = typer.Argument(..., help="Initial resource type to scan"),
|
|
228
|
+
output_dir: Path = typer.Option("generated", "-o", "--output-dir"),
|
|
229
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p"),
|
|
230
|
+
region: Optional[str] = typer.Option(None, "--region", "-r"),
|
|
231
|
+
subscription_id: Optional[str] = typer.Option(None, "--subscription-id", "-s"),
|
|
232
|
+
project_id: Optional[str] = typer.Option(None, "--project-id"),
|
|
233
|
+
zone: Optional[str] = typer.Option(None, "--zone", "-z"),
|
|
234
|
+
use_cache: bool = typer.Option(True, "--cache/--no-cache")
|
|
235
|
+
):
|
|
236
|
+
"""(Professional Feature) Recursively scan cloud resources with smart dependency resolution."""
|
|
237
|
+
from datetime import timedelta
|
|
238
|
+
from terraback.utils.scan_cache import get_scan_cache
|
|
239
|
+
from terraback.utils.cross_scan_registry import recursive_scan as base_recursive_scan
|
|
240
|
+
|
|
241
|
+
# Normalize resource type
|
|
242
|
+
resource_type_map = {
|
|
243
|
+
# Azure aliases
|
|
244
|
+
'vm': 'azure_virtual_machine',
|
|
245
|
+
'vms': 'azure_virtual_machine',
|
|
246
|
+
'disk': 'azure_managed_disk',
|
|
247
|
+
'disks': 'azure_managed_disk',
|
|
248
|
+
'vnet': 'azure_virtual_network',
|
|
249
|
+
'vnets': 'azure_virtual_network',
|
|
250
|
+
'subnet': 'azure_subnet',
|
|
251
|
+
'subnets': 'azure_subnet',
|
|
252
|
+
'nsg': 'azure_network_security_group',
|
|
253
|
+
'nsgs': 'azure_network_security_group',
|
|
254
|
+
# AWS aliases
|
|
255
|
+
'instance': 'ec2',
|
|
256
|
+
'instances': 'ec2',
|
|
257
|
+
'bucket': 's3_bucket',
|
|
258
|
+
'buckets': 's3_bucket',
|
|
259
|
+
# GCP aliases
|
|
260
|
+
'gcp_vm': 'gcp_instance',
|
|
261
|
+
'gcp_vms': 'gcp_instance',
|
|
262
|
+
'gcp_bucket': 'gcp_bucket',
|
|
263
|
+
'gcp_buckets': 'gcp_bucket',
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
normalized_type = resource_type_map.get(resource_type.lower(), resource_type.lower())
|
|
267
|
+
typer.echo(f"Starting Professional recursive scan for '{normalized_type}'...")
|
|
268
|
+
|
|
269
|
+
is_azure = normalized_type.startswith('azure_')
|
|
270
|
+
is_gcp = normalized_type.startswith('gcp_')
|
|
271
|
+
|
|
272
|
+
kwargs = {
|
|
273
|
+
'resource_type': normalized_type,
|
|
274
|
+
'output_dir': output_dir
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if is_azure:
|
|
278
|
+
from terraback.cli.azure.session import get_default_subscription_id
|
|
279
|
+
if not subscription_id:
|
|
280
|
+
subscription_id = get_default_subscription_id()
|
|
281
|
+
if not subscription_id:
|
|
282
|
+
typer.echo("Error: No Azure subscription found. Please run 'az login'", err=True)
|
|
283
|
+
raise typer.Exit(code=1)
|
|
284
|
+
kwargs['subscription_id'] = subscription_id
|
|
285
|
+
kwargs['location'] = region
|
|
286
|
+
elif is_gcp:
|
|
287
|
+
from terraback.cli.gcp.session import get_default_project_id
|
|
288
|
+
if not project_id:
|
|
289
|
+
project_id = get_default_project_id()
|
|
290
|
+
if not project_id:
|
|
291
|
+
typer.echo("Error: No GCP project found. Please run 'gcloud config set project'", err=True)
|
|
292
|
+
raise typer.Exit(code=1)
|
|
293
|
+
kwargs['project_id'] = project_id
|
|
294
|
+
kwargs['region'] = region
|
|
295
|
+
kwargs['zone'] = zone
|
|
296
|
+
else:
|
|
297
|
+
# AWS
|
|
298
|
+
from terraback.cli.common.defaults import get_aws_defaults
|
|
299
|
+
defaults = get_aws_defaults()
|
|
300
|
+
kwargs['profile'] = profile or defaults['profile']
|
|
301
|
+
kwargs['region'] = region or defaults['region']
|
|
302
|
+
|
|
303
|
+
if use_cache:
|
|
304
|
+
cache = get_scan_cache(
|
|
305
|
+
cache_dir=output_dir / ".terraback" / "cache",
|
|
306
|
+
ttl=timedelta(minutes=60)
|
|
307
|
+
)
|
|
308
|
+
typer.echo("Caching enabled (TTL: 60 minutes)")
|
|
309
|
+
|
|
310
|
+
base_recursive_scan(**kwargs)
|
|
311
|
+
|
|
312
|
+
if use_cache:
|
|
313
|
+
stats = cache.get_stats()
|
|
314
|
+
typer.echo(f"\nCache Statistics:")
|
|
315
|
+
typer.echo(f" Hit Rate: {stats['hit_rate']}")
|
|
316
|
+
typer.echo(f" Cache Size: {stats['total_size_kb']} KB")
|
|
317
|
+
|
|
318
|
+
@app.command("auth-check")
|
|
319
|
+
def check_auth():
|
|
320
|
+
"""Check authentication status for all cloud providers."""
|
|
321
|
+
typer.echo("Checking cloud authentication status...\n")
|
|
322
|
+
|
|
323
|
+
# Check AWS
|
|
324
|
+
try:
|
|
325
|
+
from terraback.cli.aws.session import get_boto_session
|
|
326
|
+
session = get_boto_session()
|
|
327
|
+
sts = session.client('sts')
|
|
328
|
+
identity = sts.get_caller_identity()
|
|
329
|
+
typer.echo("AWS: Authenticated")
|
|
330
|
+
typer.echo(f" Account: {identity['Account']}")
|
|
331
|
+
typer.echo(f" User/Role: {identity['Arn'].split('/')[-1]}")
|
|
332
|
+
typer.echo(f" Region: {session.region_name}")
|
|
333
|
+
except Exception:
|
|
334
|
+
typer.echo("AWS: Not authenticated (run: aws configure)")
|
|
335
|
+
|
|
336
|
+
# Check Azure
|
|
337
|
+
try:
|
|
338
|
+
from terraback.cli.azure.session import get_default_subscription_id
|
|
339
|
+
sub_id = get_default_subscription_id()
|
|
340
|
+
if sub_id:
|
|
341
|
+
typer.echo("\nAzure: Authenticated")
|
|
342
|
+
typer.echo(f" Subscription: {sub_id}")
|
|
343
|
+
else:
|
|
344
|
+
typer.echo("\nAzure: Not authenticated (run: az login)")
|
|
345
|
+
except Exception:
|
|
346
|
+
typer.echo("\nAzure: Not authenticated (run: az login)")
|
|
347
|
+
|
|
348
|
+
# Check GCP
|
|
349
|
+
try:
|
|
350
|
+
from terraback.cli.gcp.session import get_default_project_id
|
|
351
|
+
project_id = get_default_project_id()
|
|
352
|
+
if project_id:
|
|
353
|
+
typer.echo("\nGCP: Authenticated")
|
|
354
|
+
typer.echo(f" Project: {project_id}")
|
|
355
|
+
else:
|
|
356
|
+
typer.echo("\nGCP: Not authenticated (run: gcloud auth application-default login)")
|
|
357
|
+
except Exception:
|
|
358
|
+
typer.echo("\nGCP: Not authenticated (run: gcloud auth application-default login)")
|
|
359
|
+
|
|
360
|
+
@app.command("upgrade")
|
|
361
|
+
def upgrade_info():
|
|
362
|
+
"""Show information about upgrading to Professional features."""
|
|
363
|
+
current_tier = get_active_tier()
|
|
364
|
+
|
|
365
|
+
if current_tier == Tier.COMMUNITY:
|
|
366
|
+
typer.echo("Upgrade to Professional for Advanced Features\n")
|
|
367
|
+
|
|
368
|
+
typer.echo("Your Current Plan: Community Edition (Free)")
|
|
369
|
+
typer.echo(" - Unlimited core resources (EC2, VPC, S3, VMs, VNets, Storage)")
|
|
370
|
+
typer.echo(" - Multi-cloud support (AWS, Azure, GCP)")
|
|
371
|
+
typer.echo(" - Basic dependency mapping\n")
|
|
372
|
+
|
|
373
|
+
typer.echo("Unlock with Migration Pass ($299 for 3 months):")
|
|
374
|
+
typer.echo(" - Advanced AWS services (RDS, Lambda, EKS, ALB, Route53, etc.)")
|
|
375
|
+
typer.echo(" - Recursive dependency scanning (--with-deps)")
|
|
376
|
+
typer.echo(" - Multi-account/subscription support")
|
|
377
|
+
typer.echo(" - Priority email support")
|
|
378
|
+
typer.echo(" - Advanced caching and performance features\n")
|
|
379
|
+
|
|
380
|
+
typer.echo("Get Migration Pass: https://terraback.io/pricing")
|
|
381
|
+
typer.echo("Enterprise needs: sales@terraback.io")
|
|
382
|
+
elif current_tier == Tier.PROFESSIONAL:
|
|
383
|
+
typer.secho("You have Professional access!", fg=typer.colors.GREEN, bold=True)
|
|
384
|
+
typer.echo("All advanced features are unlocked.")
|
|
385
|
+
elif current_tier == Tier.ENTERPRISE:
|
|
386
|
+
typer.secho("You have Enterprise access!", fg=typer.colors.GREEN, bold=True)
|
|
387
|
+
typer.echo("All features including enterprise support are available.")
|
|
388
|
+
|
|
389
|
+
if __name__ == "__main__":
|
|
390
|
+
app()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from terraback.core.license import require_professional
|
|
2
|
+
import typer
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .certificates import scan_certificates, list_certificates, import_certificate
|
|
6
|
+
|
|
7
|
+
from terraback.utils.cross_scan_registry import register_scan_function, cross_scan_registry
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(
|
|
10
|
+
name="acm",
|
|
11
|
+
help="Manage AWS Certificate Manager (ACM) resources like SSL/TLS certificates.",
|
|
12
|
+
no_args_is_help=True
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# --- Certificate Commands ---
|
|
16
|
+
@app.command(name="scan-certificates", help="Scan ACM SSL/TLS certificates.")
|
|
17
|
+
@require_professional
|
|
18
|
+
def scan_certificates_command(
|
|
19
|
+
output_dir: Path = typer.Option("generated", help="Directory to save Terraform files"),
|
|
20
|
+
profile: str = typer.Option(None, help="AWS CLI profile to use"),
|
|
21
|
+
region: str = typer.Option("us-east-1", help="AWS region"),
|
|
22
|
+
include_imported: bool = typer.Option(True, help="Include imported certificates"),
|
|
23
|
+
include_issued: bool = typer.Option(True, help="Include ACM-issued certificates")
|
|
24
|
+
):
|
|
25
|
+
scan_certificates(output_dir, profile, region, include_imported, include_issued)
|
|
26
|
+
|
|
27
|
+
@app.command(name="list-certificates", help="List scanned ACM certificates.")
|
|
28
|
+
@require_professional
|
|
29
|
+
def list_certificates_command(output_dir: Path = typer.Option("generated")):
|
|
30
|
+
list_certificates(output_dir)
|
|
31
|
+
|
|
32
|
+
@app.command(name="import-certificate", help="Import an ACM certificate by ARN.")
|
|
33
|
+
@require_professional
|
|
34
|
+
def import_certificate_command(
|
|
35
|
+
certificate_arn: str,
|
|
36
|
+
output_dir: Path = typer.Option("generated")
|
|
37
|
+
):
|
|
38
|
+
import_certificate(certificate_arn, output_dir)
|
|
39
|
+
|
|
40
|
+
# --- Registration ---
|
|
41
|
+
def register():
|
|
42
|
+
"""Registers scan functions and dependencies for the ACM module."""
|
|
43
|
+
register_scan_function("acm_certificate", scan_certificates)
|
|
44
|
+
|
|
45
|
+
# ACM certificates are dependencies for other services
|
|
46
|
+
# Load balancers use ACM certificates for HTTPS listeners
|
|
47
|
+
cross_scan_registry.register_dependency("elbv2_listener", "acm_certificate")
|
|
48
|
+
# Classic load balancers can also use ACM certificates
|
|
49
|
+
cross_scan_registry.register_dependency("classic_load_balancer", "acm_certificate")
|
|
50
|
+
# API Gateway can use ACM certificates for custom domains
|
|
51
|
+
cross_scan_registry.register_dependency("api_gateway_rest_api", "acm_certificate")
|
|
52
|
+
# CloudFront distributions use ACM certificates (when we add CloudFront)
|
|
53
|
+
cross_scan_registry.register_dependency("cloudfront_distribution", "acm_certificate")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from terraback.cli.aws.session import get_boto_session
|
|
3
|
+
from terraback.terraform_generator.writer import generate_tf
|
|
4
|
+
from terraback.terraform_generator.imports import generate_imports_file
|
|
5
|
+
from terraback.utils.importer import ImportManager
|
|
6
|
+
|
|
7
|
+
def scan_certificates(
|
|
8
|
+
output_dir: Path,
|
|
9
|
+
profile: str = None,
|
|
10
|
+
region: str = "us-east-1",
|
|
11
|
+
include_imported: bool = True,
|
|
12
|
+
include_issued: bool = True
|
|
13
|
+
):
|
|
14
|
+
"""
|
|
15
|
+
Scans for ACM certificates and generates Terraform code.
|
|
16
|
+
"""
|
|
17
|
+
boto_session = get_boto_session(profile, region)
|
|
18
|
+
acm_client = boto_session.client("acm")
|
|
19
|
+
|
|
20
|
+
print(f"Scanning for ACM certificates in region {region}...")
|
|
21
|
+
|
|
22
|
+
# Build certificate status filters based on options
|
|
23
|
+
certificate_statuses = []
|
|
24
|
+
if include_issued:
|
|
25
|
+
certificate_statuses.extend(['ISSUED'])
|
|
26
|
+
if include_imported:
|
|
27
|
+
certificate_statuses.extend(['ISSUED']) # Imported certs also show as ISSUED
|
|
28
|
+
|
|
29
|
+
if not certificate_statuses:
|
|
30
|
+
print("No certificate types selected for scanning")
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
# Get all certificates using pagination
|
|
34
|
+
paginator = acm_client.get_paginator('list_certificates')
|
|
35
|
+
certificates = []
|
|
36
|
+
|
|
37
|
+
for page in paginator.paginate(CertificateStatuses=certificate_statuses):
|
|
38
|
+
for cert_summary in page['CertificateSummaryList']:
|
|
39
|
+
cert_arn = cert_summary['CertificateArn']
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
# Get detailed certificate information
|
|
43
|
+
cert_detail = acm_client.describe_certificate(CertificateArn=cert_arn)
|
|
44
|
+
certificate = cert_detail['Certificate']
|
|
45
|
+
|
|
46
|
+
# Add computed fields for easier template usage
|
|
47
|
+
certificate['arn_sanitized'] = cert_arn.split('/')[-1].replace('-', '_').lower()
|
|
48
|
+
certificate['domain_sanitized'] = certificate['DomainName'].replace('.', '_').replace('*', 'wildcard').replace('-', '_').lower()
|
|
49
|
+
|
|
50
|
+
# Determine certificate type (ACM-issued vs imported)
|
|
51
|
+
if certificate.get('Type') == 'IMPORTED':
|
|
52
|
+
certificate['is_imported'] = True
|
|
53
|
+
certificate['is_acm_issued'] = False
|
|
54
|
+
else:
|
|
55
|
+
certificate['is_imported'] = False
|
|
56
|
+
certificate['is_acm_issued'] = True
|
|
57
|
+
|
|
58
|
+
# Format subject alternative names for easier template usage
|
|
59
|
+
if certificate.get('SubjectAlternativeNames'):
|
|
60
|
+
certificate['sans_formatted'] = certificate['SubjectAlternativeNames']
|
|
61
|
+
else:
|
|
62
|
+
certificate['sans_formatted'] = []
|
|
63
|
+
|
|
64
|
+
# Format domain validation options
|
|
65
|
+
if certificate.get('DomainValidationOptions'):
|
|
66
|
+
certificate['domain_validation_formatted'] = []
|
|
67
|
+
for dvo in certificate['DomainValidationOptions']:
|
|
68
|
+
formatted_dvo = {
|
|
69
|
+
'DomainName': dvo['DomainName'],
|
|
70
|
+
'ValidationDomain': dvo.get('ValidationDomain'),
|
|
71
|
+
'ValidationStatus': dvo.get('ValidationStatus'),
|
|
72
|
+
'ValidationMethod': dvo.get('ValidationMethod')
|
|
73
|
+
}
|
|
74
|
+
# Add DNS validation records if present
|
|
75
|
+
if dvo.get('ResourceRecord'):
|
|
76
|
+
formatted_dvo['ResourceRecord'] = dvo['ResourceRecord']
|
|
77
|
+
certificate['domain_validation_formatted'].append(formatted_dvo)
|
|
78
|
+
else:
|
|
79
|
+
certificate['domain_validation_formatted'] = []
|
|
80
|
+
|
|
81
|
+
# Get certificate tags
|
|
82
|
+
try:
|
|
83
|
+
tags_response = acm_client.list_tags_for_certificate(CertificateArn=cert_arn)
|
|
84
|
+
certificate['Tags'] = tags_response.get('Tags', [])
|
|
85
|
+
except Exception as e:
|
|
86
|
+
print(f" - Warning: Could not retrieve tags for certificate {cert_arn}: {e}")
|
|
87
|
+
certificate['Tags'] = []
|
|
88
|
+
|
|
89
|
+
certificates.append(certificate)
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f" - Warning: Could not retrieve details for certificate {cert_arn}: {e}")
|
|
93
|
+
continue
|
|
94
|
+
|
|
95
|
+
# Filter certificates based on type if needed
|
|
96
|
+
if not include_imported:
|
|
97
|
+
certificates = [cert for cert in certificates if not cert['is_imported']]
|
|
98
|
+
if not include_issued:
|
|
99
|
+
certificates = [cert for cert in certificates if not cert['is_acm_issued']]
|
|
100
|
+
|
|
101
|
+
output_file = output_dir / "acm_certificate.tf"
|
|
102
|
+
generate_tf(certificates, "acm_certificate", output_file)
|
|
103
|
+
print(f"Generated Terraform for {len(certificates)} ACM certificates -> {output_file}")
|
|
104
|
+
generate_imports_file(
|
|
105
|
+
"acm_certificate",
|
|
106
|
+
certificates,
|
|
107
|
+
remote_resource_id_key="CertificateArn",
|
|
108
|
+
output_dir=output_dir
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def list_certificates(output_dir: Path):
|
|
112
|
+
"""Lists all ACM certificate resources previously generated."""
|
|
113
|
+
ImportManager(output_dir, "acm_certificate").list_all()
|
|
114
|
+
|
|
115
|
+
def import_certificate(certificate_arn: str, output_dir: Path):
|
|
116
|
+
"""Runs terraform import for a specific ACM certificate by its ARN."""
|
|
117
|
+
ImportManager(output_dir, "acm_certificate").find_and_import(certificate_arn)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from terraback.core.license import require_professional
|
|
2
|
+
import typer
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from .rest_apis import scan_rest_apis
|
|
5
|
+
|
|
6
|
+
from terraback.utils.cross_scan_registry import register_scan_function, cross_scan_registry
|
|
7
|
+
|
|
8
|
+
app = typer.Typer(
|
|
9
|
+
name="apigateway",
|
|
10
|
+
help="Manage API Gateway REST API resources.",
|
|
11
|
+
no_args_is_help=True
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
@app.command(name="scan-rest-apis", help="Scan REST APIs and all their sub-resources.")
|
|
15
|
+
@require_professional
|
|
16
|
+
def scan_apis_command(output_dir: Path = typer.Option("generated"), profile: str = typer.Option(None), region: str = typer.Option("us-east-1")):
|
|
17
|
+
scan_rest_apis(output_dir, profile, region)
|
|
18
|
+
|
|
19
|
+
# Note: list and import commands are omitted for now due to the complexity of nested resources.
|
|
20
|
+
|
|
21
|
+
def register():
|
|
22
|
+
"""Registers scan functions and dependencies for the API Gateway module."""
|
|
23
|
+
register_scan_function("api_gateway_rest_api", scan_rest_apis)
|
|
24
|
+
|
|
25
|
+
# Define dependencies
|
|
26
|
+
cross_scan_registry.register_dependency("api_gateway_integration", "lambda_function")
|
|
27
|
+
cross_scan_registry.register_dependency("lambda_function", "api_gateway_rest_api")
|