Migrating AWS Terraform to Frostmoln
To run a conversion, see the migration guide.
This matrix lists how the converter handles each supported resource type and attribute.
data.aws_ami → frostmoln_image — partially supported
The aws_ami data source maps to the frostmoln_image data source: images resolve by exact name, so a name is derived from the AMI name filter (or a reviewed placeholder is emitted) and the filter machinery disappears.
Platform images are selected by exact name. The converter derives a name guess from a filter { name = "name" } value (path segments and wildcards stripped) and upgrades it to an exact catalog name when the catalog knows it; verify the result against fm compute image list. Owner and recency selection have no equivalent.
| Attribute | Outcome | Notes |
|---|---|---|
| most_recent | Not needed on Frostmoln | |
| owners | Not needed on Frostmoln | |
| executable_users | Not needed on Frostmoln | |
| filter | Not needed on Frostmoln | |
| name_regex | Not carried over | |
| include_deprecated | Not carried over |
- The converter adds
nameautomatically. frostmoln_image resolves by name; it is derived from the AMI name filter and needs review unless the catalog confirms it.
aws_autoscaling_group → frostmoln_scale_group — partially supported
Auto Scaling groups map to frostmoln_scale_group (sizes, subnets, health checks, cooldown, target pools); the launch_template block flattens to launch_template_id.
launch_template blocks flatten to launch_template_id, with the reference rewritten to the converted frostmoln_launch_template (name-based references still need manual work). target_group_arns become load_balancer_pool_ids with references rewritten to the converted pools.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | |
| min_size | Mapped to min_size | |
| max_size | Mapped to max_size | |
| desired_capacity | Mapped to desired_capacity | |
| vpc_zone_identifier | Mapped to subnet_ids | |
| launch_template | Converted to launch_template_id | The launch_template block flattens to launch_template_id referencing the converted frostmoln_launch_template; version pinning is dropped (launch templates are not versioned). |
| launch_configuration | Manual action required | |
| mixed_instances_policy | Manual action required | |
| target_group_arns | Mapped to load_balancer_pool_ids | References are rewritten to the converted frostmoln_lb_pool resources. |
| health_check_type | Converted | |
| health_check_grace_period | Mapped to health_check_grace_period | |
| default_cooldown | Mapped to cooldown_seconds | |
| default_instance_warmup | Mapped to warmup_seconds | |
| termination_policies | Converted to termination_policy | |
| tag (also matches tags) | Manual action required | |
| availability_zones | Not carried over | |
| load_balancers | Manual action required | |
| capacity_rebalance | Not carried over | |
| instance_refresh | Not carried over | |
| warm_pool | Not carried over | |
| suspended_processes | Not carried over | |
| enabled_metrics | Not carried over | |
| metrics_granularity | Not carried over | |
| placement_group | Manual action required | |
| service_linked_role_arn | Not needed on Frostmoln | |
| max_instance_lifetime | Not carried over | |
| instance_maintenance_policy | Not carried over | |
| protect_from_scale_in | Not carried over | |
| desired_capacity_type | Not carried over | |
| wait_for_capacity_timeout | Not needed on Frostmoln | |
| wait_for_elb_capacity | Not needed on Frostmoln | |
| min_elb_capacity | Not needed on Frostmoln | |
| force_delete | Not needed on Frostmoln | |
| force_delete_warm_pool | Not needed on Frostmoln | |
| ignore_failed_scaling_activities | Not needed on Frostmoln |
- The converter adds
launch_template_idautomatically. the group carried no launch_template block; create a frostmoln_launch_template and reference it here. - The converter adds
desired_capacityautomatically. frostmoln_scale_group requires desired_capacity; when the source omits it, the min_size expression is copied verbatim. A group with neither desired_capacity nor min_size blocks - set desired_capacity manually.
aws_ebs_snapshot → frostmoln_snapshot — supported
EBS snapshots map to frostmoln_snapshot; a required snapshot name is synthesized from the Name tag or the resource address.
Snapshot archiving/restore tiers have no equivalent.
| Attribute | Outcome | Notes |
|---|---|---|
| volume_id | Mapped to volume_id | |
| description | Mapped to description | |
| tags | Converted | |
| storage_tier | Not carried over | |
| permanent_restore | Not carried over | |
| temporary_restore_days | Not carried over | |
| outpost_arn | Manual action required |
- The converter adds
nameautomatically. frostmoln_snapshot requires a name; it is taken from the Name tag or the resource address.
aws_ebs_volume → frostmoln_volume — partially supported
EBS volumes map to frostmoln_volume; the EBS volume type is dropped (the platform's default tier applies) and IOPS/throughput are set by the volume tier.
Volume tiers are platform-defined — pick a volume_type from the volume tiers catalog (frostmoln_volume_tiers data source) after the conversion; a catalog-driven tier mapping arrives in a later release. A required volume name is synthesized from the Name tag or the resource address.
| Attribute | Outcome | Notes |
|---|---|---|
| size | Mapped to size_gb | |
| availability_zone | Converted | The zone is omitted - the platform picks it; set zone to a zone id to pin one (the frostmoln_regions data source exposes both zone ids and names). |
| type | Not carried over | A catalog-driven tier mapping arrives in a later release. |
| encrypted | Mapped to encrypted | |
| snapshot_id | Mapped to snapshot_id | |
| iops | Not carried over | |
| throughput | Not carried over | |
| kms_key_id | Manual action required | |
| multi_attach_enabled | Manual action required | |
| final_snapshot | Not carried over | |
| outpost_arn | Manual action required | |
| tags | Converted |
- The converter adds
nameautomatically. frostmoln_volume requires a name; it is taken from the Name tag or the resource address.
aws_eip → frostmoln_public_ip — partially supported
Elastic IPs map to frostmoln_public_ip; a specific address cannot be requested — the platform allocates one.
An aws_eip_association referencing the EIP merges into the public IP as instance_id. public_ip references become the public IP's address.
| Attribute | Outcome | Notes |
|---|---|---|
| instance | Mapped to instance_id | |
| domain (also matches vpc) | Not needed on Frostmoln | |
| tags | Converted | |
| address | Manual action required | |
| public_ipv4_pool | Manual action required | |
| customer_owned_ipv4_pool | Manual action required | |
| associate_with_private_ip | Manual action required | |
| network_border_group | Not carried over | |
| network_interface | Manual action required |
aws_eip_association → frostmoln_public_ip — partially supported
EIP associations merge into the frostmoln_public_ip they reference: the association resource disappears and the public IP gains instance_id.
Only associations that reference a same-module aws_eip by allocation_id and target an instance can merge. Network-interface and private-IP associations have no equivalent.
| Attribute | Outcome | Notes |
|---|---|---|
| allocation_id | Converted | Selects the public IP that receives the association. |
| instance_id | Converted | Becomes instance_id on the merged frostmoln_public_ip. |
| allow_reassociation | Not needed on Frostmoln | |
| network_interface_id | Manual action required | |
| private_ip_address | Manual action required | |
| public_ip | Manual action required |
aws_instance → frostmoln_instance — partially supported
EC2 instances map to frostmoln_instance: the AMI becomes a frostmoln_image lookup, the instance type is capability-matched to a flavor, and a public IP becomes a generated frostmoln_public_ip; block devices and IAM instance profiles need manual work.
instance_type is matched against the platform flavor catalog (smallest active flavor with at least the source vCPUs and RAM) and emitted as a data "frostmoln_flavor" lookup — offline without a populated catalog a reviewed placeholder is emitted instead. The AMI becomes a data "frostmoln_image" lookup whose name needs review (fm compute image list). availability_zone is omitted (the platform picks the zone; set zone to pin one). Inline block devices are blocked — recreate them as frostmoln_volume + frostmoln_volume_attachment. A required instance name is synthesized from the Name tag or the resource address.
| Attribute | Outcome | Notes |
|---|---|---|
| ami | Converted to image_id | A literal AMI id becomes a frostmoln_image data source with a reviewed placeholder name; a data.aws_ami reference is rewritten to the converted image data source. |
| instance_type | Converted to flavor_id | Capability-matched against the platform flavor catalog and emitted as a frostmoln_flavor data source lookup by name. |
| availability_zone | Converted | The platform picks the zone; set zone to pin one. |
| subnet_id | Mapped to subnet_id | |
| vpc_security_group_ids | Mapped to security_groups | |
| security_groups | Manual action required | |
| key_name | Converted to ssh_key_names | frostmoln_instance takes a set of SSH key names. |
| user_data | Mapped to user_data | |
| user_data_base64 | Converted to user_data | frostmoln_instance takes plain-text user data. |
| user_data_replace_on_change | Not needed on Frostmoln | |
| associate_public_ip_address | Converted | A true value becomes a generated frostmoln_public_ip bound to the instance. |
| tags | Converted | |
| volume_tags | Not carried over | |
| private_ip | Not carried over | |
| secondary_private_ips | Manual action required | |
| iam_instance_profile | Manual action required | |
| root_block_device | Manual action required | A volume split arrives in a later release. |
| ebs_block_device | Manual action required | A volume split arrives in a later release. |
| ephemeral_block_device | Manual action required | |
| network_interface | Manual action required | |
| ipv6_address_count | Manual action required | |
| ipv6_addresses | Manual action required | |
| monitoring | Not needed on Frostmoln | |
| ebs_optimized | Not needed on Frostmoln | |
| metadata_options | Not needed on Frostmoln | |
| credit_specification | Not needed on Frostmoln | |
| source_dest_check | Not carried over | |
| tenancy | Not carried over | |
| host_id | Manual action required | |
| host_resource_group_arn | Manual action required | |
| placement_group | Manual action required | |
| placement_partition_number | Manual action required | |
| cpu_options (also matches cpu_core_count, cpu_threads_per_core) | Not carried over | |
| hibernation | Not carried over | |
| disable_api_termination | Not carried over | |
| disable_api_stop | Not carried over | |
| instance_initiated_shutdown_behavior | Not carried over | |
| instance_market_options | Manual action required | |
| capacity_reservation_specification | Not carried over | |
| get_password_data | Not carried over | |
| launch_template | Manual action required | |
| maintenance_options | Not carried over | |
| private_dns_name_options | Not carried over | |
| enclave_options | Manual action required |
- The converter adds
nameautomatically. frostmoln_instance requires a name; it is taken from the Name tag or the resource address. - The converter adds
flavor_idautomatically. frostmoln_instance requires a flavor; this instance pinned no instance_type (a launch-template-driven instance), so set flavor_id to a platform flavor (seefm compute flavor list). - The converter adds
image_idautomatically. frostmoln_instance requires an image; this instance pinned no ami (a launch-template-driven instance), so set image_id to a platform image (seefm compute image list).
aws_key_pair → frostmoln_ssh_key — supported
EC2 key pairs map directly to frostmoln_ssh_key.
The key name becomes the resource id; tags are not supported on SSH keys.
| Attribute | Outcome | Notes |
|---|---|---|
| key_name | Mapped to name | |
| key_name_prefix | Manual action required | |
| public_key | Mapped to public_key | |
| tags | Not carried over |
aws_launch_template → frostmoln_launch_template — partially supported
Launch templates map to frostmoln_launch_template: the image becomes a frostmoln_image lookup, the instance type is capability-matched to a flavor, and user data is decoded from base64; the required vpc_id must be set manually.
instance_type is matched against the platform flavor catalog and emitted as a data "frostmoln_flavor" lookup; image_id becomes a data "frostmoln_image" lookup whose name needs review. key_name carries a key NAME but frostmoln_launch_template takes ssh_key_ids — replace the wrapped name with the frostmoln_ssh_key id. frostmoln_launch_template requires vpc_id, which AWS launch templates do not carry: a placeholder is synthesized. Launch templates are not versioned on Frostmoln.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | |
| description | Not carried over | |
| image_id | Converted | A literal AMI id becomes a frostmoln_image data source with a reviewed placeholder name; a data.aws_ami reference is rewritten to the converted image data source. |
| instance_type | Converted to flavor_id | Capability-matched against the platform flavor catalog and emitted as a frostmoln_flavor data source lookup by name. |
| key_name | Converted to ssh_key_ids | The key NAME is wrapped into a set, but ssh_key_ids takes key IDs — replace it with the frostmoln_ssh_key id. |
| vpc_security_group_ids | Mapped to security_group_ids | |
| security_group_names | Manual action required | |
| user_data | Converted | AWS launch-template user data is base64; frostmoln_launch_template takes plain text. |
| tags | Converted | |
| tag_specifications | Manual action required | |
| default_version | Not needed on Frostmoln | |
| update_default_version | Not needed on Frostmoln | |
| block_device_mappings | Manual action required | A volume split arrives in a later release. |
| network_interfaces | Manual action required | |
| iam_instance_profile | Manual action required | |
| instance_market_options | Manual action required | |
| instance_requirements | Manual action required | |
| placement | Manual action required | |
| monitoring | Not needed on Frostmoln | |
| ebs_optimized | Not needed on Frostmoln | |
| metadata_options | Not needed on Frostmoln | |
| credit_specification | Not needed on Frostmoln | |
| cpu_options | Not carried over | |
| kernel_id | Not carried over | |
| ram_disk_id | Not carried over | |
| disable_api_stop | Not carried over | |
| disable_api_termination | Not carried over | |
| instance_initiated_shutdown_behavior | Not carried over | |
| hibernation_options | Not carried over | |
| elastic_gpu_specifications (retired by the provider) | Manual action required | |
| elastic_inference_accelerator (retired by the provider) | Manual action required | |
| enclave_options | Manual action required | |
| license_specification | Not carried over | |
| maintenance_options | Not carried over | |
| private_dns_name_options | Not carried over | |
| capacity_reservation_specification | Not carried over |
- The converter adds
nameautomatically. frostmoln_launch_template requires a name; it is taken from the Name tag or the resource address. - The converter adds
vpc_idautomatically. frostmoln_launch_template requires the target VPC; set vpc_id to the converted frostmoln_vpc id. - The converter adds
flavor_idautomatically. frostmoln_launch_template requires a flavor; the source template did not pin an instance type. - The converter adds
image_idautomatically. frostmoln_launch_template requires an image; the source template did not pin one.
aws_lb → frostmoln_load_balancer — partially supported
Application and network load balancers map to frostmoln_load_balancer; Frostmoln LBs attach to a single subnet, and security groups move to listener allowed_cidrs.
internal = true/false becomes scheme = "internal"/"public" — note that aws_lb defaults to internet-facing while frostmoln_load_balancer defaults to internal, and a public scheme requires a public_ip_id. The required vpc_id cannot be derived from the source and is emitted as an FM-TODO placeholder. load_balancer_type application/network becomes provider_type amphora/ovn.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | |
| internal | Converted to scheme | A public scheme requires a public_ip_id — create a frostmoln_public_ip for the load balancer. |
| load_balancer_type | Converted to provider_type | |
| subnets | Converted to subnet_id | |
| subnet_mapping | Manual action required | |
| security_groups | Not carried over | |
| tags | Converted | |
| enable_deletion_protection | Not carried over | |
| access_logs | Manual action required | |
| connection_logs | Manual action required | |
| idle_timeout | Not carried over | |
| enable_http2 | Not carried over | |
| enable_cross_zone_load_balancing | Not needed on Frostmoln | |
| ip_address_type | Not carried over | |
| drop_invalid_header_fields | Not carried over | |
| preserve_host_header | Not carried over | |
| xff_header_processing_mode | Not carried over | |
| desync_mitigation_mode | Not carried over | |
| enable_waf_fail_open | Not carried over | |
| dns_record_client_routing_policy | Not carried over | |
| enable_tls_version_and_cipher_suite_headers | Not carried over | |
| enable_zonal_shift | Not carried over | |
| client_keep_alive | Not carried over | |
| customer_owned_ipv4_pool | Manual action required | |
| enforce_security_group_inbound_rules_on_private_link_traffic | Not carried over |
- The converter adds
schemeautomatically. aws_lb defaults to internet-facing, so an absent internal flag becomes scheme public; a public scheme requires a public_ip_id - create a frostmoln_public_ip or set scheme to "internal". - The converter adds
vpc_idautomatically. frostmoln_load_balancer requires vpc_id; set it to the VPC of the load balancer's subnet.
aws_lb_listener → frostmoln_lb_listener — partially supported
Load-balancer listeners map to frostmoln_lb_listener; a single forward default action becomes default_pool_id, and TLS certificates must be re-uploaded.
Frostmoln listeners are deny-by-default: a required allowed_cidrs list is synthesized as ["0.0.0.0/0"] with an FM-TODO — review it. HTTPS becomes terminated_https; upload the certificate and set tls_certificate_id manually. Redirect and fixed-response actions have no equivalent.
| Attribute | Outcome | Notes |
|---|---|---|
| load_balancer_arn | Mapped to load_balancer_id | |
| port | Mapped to protocol_port | |
| protocol | Converted | |
| default_action | Converted | A single forward action becomes default_pool_id referencing the converted pool; other action types must be recreated manually. |
| ssl_policy | Not carried over | |
| certificate_arn | Manual action required | |
| alpn_policy | Not carried over | |
| mutual_authentication | Manual action required | |
| tcp_idle_timeout_seconds | Not carried over | |
| tags | Not carried over |
- The converter adds
nameautomatically. frostmoln_lb_listener requires a name; it is taken from the Name tag or the resource address.
aws_lb_target_group → frostmoln_lb_pool — partially supported
Target groups map to frostmoln_lb_pool; the inline health_check block splits into a frostmoln_lb_health_monitor, and stickiness becomes session_persistence.
frostmoln_lb_pool requires load_balancer_id, which a target group does not carry — an FM-TODO placeholder is emitted; set it to the converted load balancer. A required lb_algorithm defaults to round_robin unless load_balancing_algorithm_type maps one - note that load balancers of network type (provider_type ovn) only support source_ip_port, so change lb_algorithm when attaching this pool to an ovn load balancer. Member ports are set per frostmoln_lb_member, so the port attribute is dropped.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | |
| protocol | Converted | |
| port | Not carried over | |
| vpc_id | Not needed on Frostmoln | |
| target_type | Not needed on Frostmoln | |
| stickiness | Converted | lb_cookie becomes HTTP_COOKIE, app_cookie becomes APP_COOKIE, source_ip becomes SOURCE_IP; cookie durations are platform-managed. |
| load_balancing_algorithm_type | Converted to lb_algorithm | |
| load_balancing_anomaly_mitigation | Not carried over | |
| load_balancing_cross_zone_enabled | Not needed on Frostmoln | |
| proxy_protocol_v2 | Converted to proxy_protocol | |
| deregistration_delay | Not carried over | |
| slow_start | Not carried over | |
| preserve_client_ip | Not carried over | |
| connection_termination | Not carried over | |
| lambda_multi_value_headers_enabled | Manual action required | |
| ip_address_type | Not carried over | |
| target_failover | Not carried over | |
| target_health_state | Not carried over | |
| target_group_health | Not carried over | |
| tags | Not carried over |
Inline health_check blocks are split into frostmoln_lb_health_monitor resources:
| Block attribute | Outcome | Notes |
|---|---|---|
| protocol | Converted to type | |
| path | Mapped to url_path | |
| interval | Mapped to delay | |
| timeout | Mapped to timeout | |
| healthy_threshold | Mapped to max_retries | |
| unhealthy_threshold | Not carried over | |
| matcher | Mapped to expected_codes | |
| port | Not carried over | |
| enabled | Not carried over |
- The converter adds
lb_algorithmautomatically. frostmoln_lb_pool requires lb_algorithm; round_robin matches the AWS default. - The converter adds
load_balancer_idautomatically. frostmoln_lb_pool requires load_balancer_id; set it to the converted load balancer. - The converter adds
nameautomatically. frostmoln_lb_pool requires a name; when the source omits one it is taken from the Name tag or the resource address.
aws_lb_target_group_attachment → frostmoln_lb_member — partially supported
Target-group attachments map to frostmoln_lb_member; the member address must be an IP, so instance-id targets need review.
target_id becomes address, which must be an IP address — instance references should use the instance's private IP attribute. The required load_balancer_id is emitted as an FM-TODO placeholder.
| Attribute | Outcome | Notes |
|---|---|---|
| target_group_arn | Mapped to pool_id | |
| target_id | Converted to address | IP targets carry over directly; instance-id targets must be changed to the instance's private IP. |
| port | Mapped to protocol_port | |
| availability_zone | Not carried over |
- The converter adds
load_balancer_idautomatically. frostmoln_lb_member requires load_balancer_id; set it to the converted load balancer.
aws_route53_record → frostmoln_dns_record — partially supported
Simple DNS records map to frostmoln_dns_record; record names become zone-relative, and alias records and routing policies (weighted, latency, failover, geolocation) have no equivalent.
Supported record types: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, PTR. Record names are zone-relative on Frostmoln (the zone name is appended automatically), so fully qualified names block the conversion - strip the zone suffix, or use "@" for the apex. Alias records must be recreated as CNAME (or A) records with explicit values. Record names must be lowercase.
| Attribute | Outcome | Notes |
|---|---|---|
| zone_id | Mapped to zone_id | |
| name | Converted | Record names are zone-relative: "www" carries over, "www.example.com" blocks the conversion (the platform appends the zone name automatically). Names must be lowercase. |
| type | Converted | |
| ttl | Mapped to ttl | |
| records | Mapped to records | |
| alias | Manual action required | |
| weighted_routing_policy | Manual action required | |
| latency_routing_policy | Manual action required | |
| failover_routing_policy | Manual action required | |
| geolocation_routing_policy | Manual action required | |
| geoproximity_routing_policy | Manual action required | |
| cidr_routing_policy | Manual action required | |
| multivalue_answer_routing_policy | Manual action required | |
| set_identifier | Manual action required | |
| health_check_id | Manual action required | |
| allow_overwrite | Not needed on Frostmoln |
- The converter adds
recordsautomatically. this record has no explicit values, so it is an alias record; Frostmoln has no alias records - set the value the alias resolved to (the commented-out alias block shows its target) - The converter adds
ttlautomatically. alias records inherit their target's TTL on AWS; a frostmoln_dns_record needs an explicit one
aws_route53_zone → frostmoln_dns_zone — partially supported
Public hosted zones map to frostmoln_dns_zone; private zones are not supported, and a required SOA email is synthesized as a placeholder.
Zone names are normalized to lowercase fully qualified domains with a trailing dot (the platform requires that form). The required SOA admin email cannot come from Route 53 — an FM-TODO placeholder is emitted.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Converted | Zone names are normalized to a lowercase FQDN with a trailing dot, e.g. "example.com." |
| comment | Mapped to description | |
| tags | Converted | |
| vpc | Manual action required | |
| force_destroy | Not needed on Frostmoln | |
| delegation_set_id | Not carried over |
- The converter adds
emailautomatically. the SOA admin email is required; replace the placeholder with a real contact address.
aws_s3_bucket → frostmoln_bucket — partially supported
S3 buckets map to frostmoln_bucket (name, region, storage class, tags, versioning); ACLs, policies, website hosting, CORS, logging, replication, and object lock have no equivalent.
An aws_s3_bucket_versioning resource referencing the bucket merges into the versioning attribute. Objects are stored on encrypted disks, so SSE configuration disappears. Buckets are private by default and customer credentials cannot change that - re-grant access with frostmoln_s3_credential narrowed to the bucket. Lifecycle rules do exist on the platform (expiration and noncurrent-version cleanup, not transitions), but frostmoln_bucket exposes no lifecycle attribute, so they are set outside Terraform.
| Attribute | Outcome | Notes |
|---|---|---|
| bucket | Mapped to name | |
| bucket_prefix | Manual action required | |
| region | Converted | Frostmoln is single-region today; the platform default region applies. |
| tags | Converted | |
| force_destroy | Not needed on Frostmoln | |
| acl | Manual action required | |
| grant | Manual action required | |
| policy | Manual action required | |
| website | Manual action required | |
| cors_rule | Manual action required | |
| lifecycle_rule | Manual action required | |
| versioning | Manual action required | |
| logging | Not carried over | |
| replication_configuration | Manual action required | |
| server_side_encryption_configuration | Manual action required | |
| object_lock_configuration | Manual action required | |
| object_lock_enabled | Manual action required | |
| acceleration_status | Not needed on Frostmoln | |
| request_payer | Not needed on Frostmoln |
aws_s3_bucket_versioning → frostmoln_bucket — partially supported
Bucket versioning resources merge into the frostmoln_bucket they reference: the resource disappears and the bucket gains versioning = "enabled" or "suspended".
Only Enabled and Suspended states merge, and the bucket must be a same-module aws_s3_bucket reference. MFA delete is not supported.
| Attribute | Outcome | Notes |
|---|---|---|
| bucket | Converted | Selects the bucket that receives the versioning attribute. |
| versioning_configuration | Converted | The status becomes versioning on the merged frostmoln_bucket ("enabled" or "suspended"). |
| expected_bucket_owner | Not needed on Frostmoln | |
| mfa | Not carried over |
aws_secretsmanager_secret → frostmoln_secret — partially supported
Secrets Manager secrets map to frostmoln_secret; the value is set on the secret itself rather than in a separate version resource.
On AWS the value lives in an aws_secretsmanager_secret_version - Frostmoln stores it on the secret and versions it internally, so a required secret_value is emitted as an FM-TODO placeholder: fill it from the corresponding version's secret_string. Two behaviours differ and are worth checking: secret NAMES are restricted to letters, digits, dots, underscores and hyphens (the idiomatic prod/db/password form is rejected, so it blocks rather than failing at apply), and the recovery window DEFAULTS to 7 days here against 30 on AWS - set recovery_window_days explicitly if you relied on the AWS default. Encryption is unconditional, so there is no key to choose; resource policies and cross-region replicas have no equivalent, and rotation is explicit rather than scheduled.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Converted | Secret names are restricted to letters, digits, dots, underscores and hyphens; a slash-separated AWS name blocks the conversion. |
| description | Mapped to description | |
| recovery_window_in_days | Mapped to recovery_window_days | Means the same thing - soft delete, then permanent purge - but the platform default is 7 days against AWS's 30, so an omitted value shortens the window. |
| tags | Converted | |
| name_prefix | Manual action required | |
| kms_key_id | Not needed on Frostmoln | |
| policy | Manual action required | |
| replica | Not needed on Frostmoln | |
| force_overwrite_replica_secret | Not needed on Frostmoln |
- The converter adds
secret_valueautomatically. frostmoln_secret holds the value inline; set secret_value from the corresponding aws_secretsmanager_secret_version's secret_string.
aws_security_group → frostmoln_security_group — partially supported
Security groups map to frostmoln_security_group; inline ingress/egress blocks are split into one frostmoln_security_group_rule per CIDR, source group, or self rule.
Frostmoln security-group rules are standalone resources, so every inline rule block fans out into frostmoln_security_group_rule resources — one per CIDR block, one per source security group, and one for self. ADDRESS FAMILY: a frostmoln_security_group_rule has no ether_type field, so every rule the platform creates is IPv4 and no converted rule can be IPv6. An ipv6_cidr_blocks entry is REFUSED as a blocker and no rule is generated for it, so a mixed-family block converts its cidr_blocks entries and is missing exactly the IPv6 half; a block whose ONLY remote is ipv6_cidr_blocks generates no rules at all and blocks in full. Do NOT translate an IPv6 range to an IPv4 one, it selects different hosts. Prefix lists are not supported either. EGRESS IS WIDENED BY CONVERSION: a Terraform-managed AWS security group denies egress unless the configuration declares it, and every Frostmoln security group is created with allow-all egress (Neutron adds one IPv4 and one IPv6 allow-any egress rule to every new group, and Frostmoln removes neither), and converted egress rules ADD to those defaults rather than replacing them. A source group with tightly restricted egress is therefore widened just as much as one with no egress block at all - declaring egress rules does NOT make the converted group faithful. The converted configuration does not manage the defaults, so no terraform apply removes them, and Neutron re-creates them whenever the group is replaced (changing vpc_id forces replacement). Deleting them restores the source posture but makes the converted rules the group's ENTIRE egress policy: confirm they cover everything the instances need outbound, including DNS and the instance metadata service; note that no converted rule is IPv6, because frostmoln_security_group_rule has no ether_type, so deleting the IPv6 default denies all IPv6 egress with no replacement expressible in Terraform; and remember egress is the UNION of every security group on the instance's ports, including the tenant's implicit default group, which has allow-all egress of its own.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | |
| description | Mapped to description | |
| vpc_id | Mapped to vpc_id | |
| tags | Converted | |
| revoke_rules_on_delete | Not needed on Frostmoln |
Inline ingress/egress blocks are split into frostmoln_security_group_rule resources (one per element of cidr_blocks, security_groups):
| Block attribute | Outcome | Notes |
|---|---|---|
| protocol | Converted | |
| from_port | Converted to port_range_min | |
| to_port | Converted to port_range_max | |
| cidr_blocks | One resource per element, becomes remote_cidr | |
| security_groups | One resource per element, becomes remote_group_id | |
| self | Converted to remote_group_id | |
| description | Mapped to description | |
| ipv6_cidr_blocks | Manual action required | |
| prefix_list_ids | Manual action required |
- The converter adds
nameautomatically. frostmoln_security_group requires a name; when the source omits one it is taken from the Name tag or the resource address.
aws_security_group_rule → frostmoln_security_group_rule — partially supported
Standalone security-group rules map to frostmoln_security_group_rule; one rule per CIDR (multi-CIDR lists must be split), and IPv6/prefix lists are not supported yet.
type becomes direction, from/to_port become port_range_min/max, and "-1" protocols become "any". A cidr_blocks list with more than one element blocks the conversion — create one frostmoln_security_group_rule per CIDR.
| Attribute | Outcome | Notes |
|---|---|---|
| type | Converted to direction | |
| protocol | Converted | |
| from_port | Converted to port_range_min | |
| to_port | Converted to port_range_max | |
| cidr_blocks | Converted to remote_cidr | |
| source_security_group_id | Mapped to remote_group_id | |
| security_group_id | Mapped to security_group_id | |
| description | Mapped to description | |
| self | Converted to remote_group_id | |
| ipv6_cidr_blocks | Manual action required | |
| prefix_list_ids | Manual action required |
data.aws_subnet → frostmoln_subnet — partially supported
The aws_subnet data source maps to the frostmoln_subnet data source, which selects a subnet by id or name (optionally narrowed by vpc_id); CIDR, zone, tag, and filter-based lookups have no equivalent.
frostmoln_subnet looks up a subnet by id or name, optionally narrowed by vpc_id. The AWS data source's alternative selectors — cidr_block, availability_zone, tags, filter blocks, and the default-for-AZ flag — block the conversion: look the subnet up by id or name instead. Attribute references (cidr_block, availability_zone, ...) are rewritten to the frostmoln_subnet data source's exported attributes.
| Attribute | Outcome | Notes |
|---|---|---|
| id | Mapped to id | |
| vpc_id | Mapped to vpc_id | |
| cidr_block | Manual action required | |
| availability_zone | Manual action required | |
| availability_zone_id | Manual action required | |
| default_for_az | Manual action required | |
| state | Manual action required | |
| tags | Manual action required | |
| filter | Manual action required |
aws_subnet → frostmoln_subnet — partially supported
Subnets map to frostmoln_subnet; the platform picks the zone, and IPv6 addressing is not supported yet.
A required subnet name is synthesized from the Name tag or the resource address. availability_zone is omitted because the platform picks the zone — set zone to a zone id to pin one (the frostmoln_regions data source exposes both zone ids and names).
| Attribute | Outcome | Notes |
|---|---|---|
| cidr_block | Mapped to cidr | |
| vpc_id | Mapped to vpc_id | |
| availability_zone | Converted | The zone is omitted - the platform picks it; set zone to a zone id to pin one (the frostmoln_regions data source exposes both zone ids and names). |
| availability_zone_id | Not carried over | |
| map_public_ip_on_launch | Not needed on Frostmoln | |
| tags | Converted | |
| assign_ipv6_address_on_creation | Manual action required | |
| ipv6_cidr_block | Manual action required | |
| ipv6_native | Manual action required | |
| enable_dns64 | Manual action required | |
| enable_resource_name_dns_a_record_on_launch | Not carried over | |
| enable_resource_name_dns_aaaa_record_on_launch | Not carried over | |
| private_dns_hostname_type_on_launch | Not carried over | |
| customer_owned_ipv4_pool | Manual action required | |
| map_customer_owned_ip_on_launch | Manual action required | |
| outpost_arn | Manual action required |
- The converter adds
nameautomatically. frostmoln_subnet requires a name; it is taken from the Name tag or the resource address.
aws_volume_attachment → frostmoln_volume_attachment — supported
Volume attachments map directly to frostmoln_volume_attachment; device_name becomes device_path.
Detach behavior flags (force_detach, skip_destroy, stop_instance_before_detaching) are platform-managed and dropped.
| Attribute | Outcome | Notes |
|---|---|---|
| device_name | Mapped to device_path | |
| volume_id | Mapped to volume_id | |
| instance_id | Mapped to instance_id | |
| force_detach | Not carried over | |
| skip_destroy | Not carried over | |
| stop_instance_before_detaching | Not carried over |
data.aws_vpc → frostmoln_vpc — partially supported
The aws_vpc data source maps to the frostmoln_vpc data source, which selects a VPC by id or name; CIDR, tag, and filter-based lookups have no equivalent.
frostmoln_vpc looks up a VPC by exactly one of id or name. The AWS data source's alternative selectors — cidr_block, tags, filter blocks, dhcp_options_id, state, and the default-VPC flag — block the conversion: look the VPC up by id or name instead. Attribute references (cidr_block, arn, ...) are rewritten to the frostmoln_vpc data source's exported attributes.
| Attribute | Outcome | Notes |
|---|---|---|
| id | Mapped to id | |
| cidr_block | Manual action required | |
| dhcp_options_id | Manual action required | |
| default | Manual action required | |
| state | Manual action required | |
| tags | Manual action required | |
| filter | Manual action required |
aws_vpc → frostmoln_vpc — partially supported
VPCs map to frostmoln_vpc; DNS options are platform defaults and IPAM/IPv6 pools are not supported yet.
A required VPC name is synthesized from the Name tag or the resource address. Platform DNS is always enabled, so the enable_dns_* flags disappear. IPv6 and IPAM-managed addressing have no equivalent yet. The converted VPC has NO outbound internet access on its own: outbound is an explicit frostmoln_gateway (one per VPC, egressing from an address the platform draws for it; name a Public IP of your own with public_ip_id where a partner allow-lists your source address, and that address is billed as a Public IP), and without it the VPC also has no DNS resolution and no managed-service connectivity, because those are reached over routes that exist only while the egress path does. The source configuration's aws_internet_gateway and aws_nat_gateway do not convert into one — see their entries.
| Attribute | Outcome | Notes |
|---|---|---|
| cidr_block | Mapped to cidr | |
| tags | Converted | |
| enable_dns_support | Not needed on Frostmoln | |
| enable_dns_hostnames | Not needed on Frostmoln | |
| instance_tenancy | Not carried over | |
| enable_network_address_usage_metrics | Not carried over | |
| ipv4_ipam_pool_id | Manual action required | |
| ipv4_netmask_length | Manual action required | |
| ipv6_cidr_block | Manual action required | |
| ipv6_ipam_pool_id | Manual action required | |
| ipv6_netmask_length | Manual action required | |
| ipv6_cidr_block_network_border_group | Manual action required | |
| assign_generated_ipv6_cidr_block | Manual action required |
- The converter adds
nameautomatically. frostmoln_vpc requires a name; it is taken from the Name tag or the resource address.
Resources without an equivalent
| Resource | What happens |
|---|---|
| data.aws_caller_identity | There is no caller-identity data source; the tenant the provider operates in is provider configuration (the frostmoln provider's tenant_id, or FROSTMOLN_TENANT_ID), so replace references with that value. |
| aws_db_subnet_group | Database subnet groups are removed; resolve to a subnet_id on the database instance. |
| aws_egress_only_internet_gateway | This is the IPv6 outbound path and Frostmoln VPCs are IPv4-only; the IPv4 outbound path is a frostmoln_gateway, a separate resource you must add. The VPC may have at most ONE, so every gateway serving it collapses into that one. |
| aws_iam_access_key | There is no IAM access key; use frostmoln_api_key for the platform API, or frostmoln_s3_credential for bucket access. |
| aws_iam_instance_profile | Instances carry no ambient cloud identity on Frostmoln; there is no instance profile to attach. |
| aws_iam_openid_connect_provider | Frostmoln does not federate an arbitrary external OIDC issuer; workload identity covers Frostmoln-managed Kubernetes only. |
| aws_iam_policy | Managed policies do not convert; Frostmoln has frostmoln_iam_policy, but its document is a different language that must be rewritten. |
| data.aws_iam_policy_document | Renders an AWS policy JSON document; Frostmoln has its own policy language, so rewrite it with the frostmoln_iam_policy_document data source. |
| aws_iam_role | Frostmoln has no assumable roles; permissions attach directly to an API key, a workload identity, or a group. |
| aws_iam_role_policy | Inline role policies do not convert; there are no roles on Frostmoln to inline a policy into. |
| aws_iam_role_policy_attachment | Policy attachments do not convert as-is; frostmoln_iam_policy_attachment attaches to a principal or group, never to a role. |
| data.aws_iam_roles | There are no assumable roles on Frostmoln to enumerate. |
| aws_iam_user | Frostmoln has no IAM users; people are organization members and machine callers are API keys. |
| aws_iam_user_policy | Inline user policies do not convert; there is no IAM user to inline a policy into. |
| aws_internet_gateway | Frostmoln splits the two directions an internet gateway carries — outbound is the VPC's frostmoln_gateway, inbound is a Public IP or a load balancer — and a converted VPC has neither until you ask for them. The VPC may have at most ONE gateway, so every gateway serving it collapses into that one. |
| aws_internet_gateway_attachment | There is no gateway to attach: a Frostmoln VPC's outbound path is its own resource (frostmoln_gateway) and inbound is per workload, never a VPC-wide attachment. The VPC may have at most ONE such resource, so every gateway serving it collapses into that one. |
| aws_main_route_table_association | Routing inside a VPC is platform-managed and main route table associations are removed; there is no main route table, and no VPC-wide default route to the internet — outbound comes from the VPC's gateway. |
| aws_nat_gateway | A Frostmoln VPC reaches the internet only while a frostmoln_gateway is attached to it, and the converter must not decide for you whether that path egresses from a platform-drawn address or from a Public IP you own. A VPC may have at most ONE, so several NAT gateways serving one VPC collapse into a single gateway. |
| aws_nat_gateway_eip_association | A frostmoln_gateway carries ONE source address — the platform's, or a single Public IP you own and name — so an association that attaches several allocated addresses has no counterpart. |
| aws_route | Routing inside a VPC is platform-managed and individual routes are removed; a default route to the internet is not one of them — outbound comes from the VPC's gateway, a separate resource you must add. |
| aws_route_table | Routing inside a VPC is platform-managed per subnet and route tables are removed; the internet default route one usually carries is not replaced — outbound comes from the VPC's gateway, a separate resource you must add. |
| aws_route_table_association | Routing inside a VPC is platform-managed and route table associations are removed; associating a subnet with a table that carried an internet default route does not carry that route over — outbound comes from the VPC's gateway. |
| aws_s3_bucket_acl | Bucket and object ACLs cannot be set from Terraform; buckets are private by default and access is granted with S3 credentials. |
| aws_s3_bucket_lifecycle_configuration | Object lifecycle rules have no Terraform surface; the platform supports expiration and noncurrent-version cleanup, but storage-class transitions do not. |
| aws_s3_bucket_ownership_controls | Object ownership is not configurable; there is no ACL or cross-account concept, so the resource is removed. |
| aws_s3_bucket_policy | There is no resource-side bucket policy; access is granted from the principal side instead. |
| aws_s3_bucket_public_access_block | Public-access blocking is the platform default; Frostmoln buckets are private and the resource is removed. |
| aws_s3_bucket_server_side_encryption_configuration | Object data is encrypted at rest unconditionally, but there is no per-bucket encryption setting and no customer-managed key. |
| aws_secretsmanager_secret_version | Secret versions have no standalone equivalent; the value is set on the frostmoln_secret directly. |
| data.aws_security_group | The aws_security_group data source has no equivalent yet: Frostmoln exposes no security-group lookup data source. Reference the converted frostmoln_security_group resource, or its id, directly. |
data.aws_caller_identity
This data source reads nothing and creates nothing - it exposes who Terraform is authenticated as. The frostmoln provider already knows: it operates in exactly ONE tenant, taken from the provider's tenant_id (or FROSTMOLN_TENANT_ID), defaulting to the account's default tenant when neither is set. Use a variable for the tenant id and pass it to the provider, then reference that variable where data.aws_caller_identity.current.account_id was used. Most uses of account_id are ARN construction, and that does not carry over either: Frostmoln identifies policy targets with FRNs, shaped frn:<service>:<region>:<tenant>:<type>/<id>, which you write as patterns in a frostmoln_iam_policy_document targets list - usually with * for the tenant segment, since a policy is already tenant-scoped, and always with * for the region segment, which is all the provider accepts today. There is no account number to interpolate, and nothing constructs an FRN for you. arn and user_id have no counterpart: the identity behind an API key is not addressable in configuration, and permissions are attached to the api_key, workload_identity, or group directly with frostmoln_iam_policy_attachment.
aws_db_subnet_group
Frostmoln database instances attach to a single subnet — set subnet_id on the frostmoln_postgres_instance/frostmoln_mysql_instance directly.
aws_egress_only_internet_gateway
An egress-only internet gateway is the IPv6 half of outbound connectivity. It has no equivalent, for two independent reasons, and both matter.
First, Frostmoln VPCs are IPv4-only today: every IPv6 attribute on the converted aws_vpc and aws_subnet blocks is a blocker for the same reason, so there is no IPv6 traffic left for this gateway to carry.
Second, its IPv4 counterpart is not automatic either. A Frostmoln VPC has no outbound path at all until a gateway is attached to it, and a VPC without one is an isolated network: no outbound internet, and — because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does — no name resolution and no managed-service connectivity either. Attach one to the converted VPC:
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
The gateway's source address is drawn by the platform, and you do not choose which one you get, so it is not an address to publish. Where a partner allow-lists your source address, or DNS points at it, allocate the address yourself and name it — the gateway then egresses from that one:
resource "frostmoln_public_ip" "egress" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.egress.id
}
That address is one of yours: listed among your Public IPs, drawn from the same public IPv4 quota your customer-facing addresses use, and billed as a Public IP. There is no shared-outbound-address option — a VPC egresses through its own gateway, never through an address held in common with other tenants. The converter writes no gateway: connectivity is a stated choice, so that a VPC cannot acquire an outbound path — or a billable public address — because a field was omitted.
The same gateway can be created outside Terraform with fm network gateway create.
It adopts rather than duplicates. If the VPC already has a gateway — one the platform attached implicitly because a public IP was associated with an instance in it, or one created outside Terraform later — import that one rather than creating a second; the platform refuses the second with GATEWAY_EXISTS. The resource is one-to-one with its VPC, so the VPC's own id is the import id:
terraform import frostmoln_gateway.main <vpc-id>
aws_iam_access_key
Both replacements ARE Terraform-managed, but neither is derived from a user resource. frostmoln_api_key issues a platform API key (its value is returned only on create). frostmoln_s3_credential issues an S3 access key id and secret, and can be narrowed with allowed_buckets, allowed_actions, and ip_whitelist. A configuration that fed this key into an application should read the replacement resource's attributes, or a frostmoln_secret.
aws_iam_instance_profile
A plain instance authenticates with an API key delivered like any other secret. A workload running in a Frostmoln-managed Kubernetes cluster uses frostmoln_workload_identity_binding instead, which binds a namespace and service account and is granted by an attached frostmoln_iam_policy (or, coarser and optional, a flat scopes list) - no static credential on the node.
aws_iam_openid_connect_provider
frostmoln_workload_identity_binding trades a projected Kubernetes ServiceAccount token from a Frostmoln-managed cluster for a short-lived platform token - it does not accept a third-party issuer, so a GitHub Actions (or other external CI) keyless-deploy trust relationship has no equivalent. Those callers need an API key held as a CI secret.
aws_iam_policy
Recreate the policy as a frostmoln_iam_policy whose document comes from the frostmoln_iam_policy_document data source, then attach it with frostmoln_iam_policy_attachment. The engine will not translate the statements: an AWS action/ARN/condition has no mechanical equivalent in Frostmoln operations, FRNs and constraints, and a wrong guess here is a permissions bug.
data.aws_iam_policy_document
This is a document renderer, not cloud infrastructure - nothing is provisioned by it. frostmoln_iam_policy_document is the direct counterpart: rule blocks with name, access, operations, targets (FRNs) and constraint blocks. The statements themselves do NOT carry over - AWS actions, ARNs and condition keys have no mechanical translation to Frostmoln operations, FRNs and constraints - so the document is rewritten by hand, not converted.
aws_iam_role
There is no trust policy and nothing to assume. Recreate what the role granted as a frostmoln_iam_policy (document from the frostmoln_iam_policy_document data source) and attach it with frostmoln_iam_policy_attachment to an api_key, workload_identity, or group. Workloads in a Frostmoln-managed Kubernetes cluster get their identity from frostmoln_workload_identity_binding - that is the closest counterpart to IRSA.
aws_iam_role_policy
Recreate the permissions as a frostmoln_iam_policy and attach it with frostmoln_iam_policy_attachment to an api_key, workload_identity, or group. The policy document must be rewritten in Frostmoln's own language (frostmoln_iam_policy_document).
aws_iam_role_policy_attachment
Frostmoln has the same shape one level down: attach the rewritten frostmoln_iam_policy to an api_key, workload_identity, or group with frostmoln_iam_policy_attachment. Whatever the role was assumed BY becomes the attachee.
data.aws_iam_roles
Organization roles exist, but they are member role assignments rather than an IAM-role listing, and there is no data source for them. Permissions live on frostmoln_iam_policy attached to an api_key, workload_identity, or group.
aws_iam_user
Invite people to the organization and assign them an organization role; for a machine caller create a frostmoln_api_key. Organization membership and role assignment are not Terraform-managed; the API key is. Permissions on top of that come from a frostmoln_iam_policy attached to the api_key or a group.
aws_iam_user_policy
Attach a rewritten frostmoln_iam_policy to the api_key or group that replaces the user (frostmoln_iam_policy_attachment).
aws_internet_gateway
An internet gateway is not a one-to-one concept, and it is emphatically not a resource the platform makes unnecessary. It carries BOTH directions; Frostmoln separates them, and neither follows from the VPC alone.
OUTBOUND is the VPC's gateway — one explicit resource per VPC. A VPC without one is an isolated network: no outbound internet, and — because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does — no name resolution and no managed-service connectivity either. Attach one to the converted VPC:
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
The gateway's source address is drawn by the platform, and you do not choose which one you get, so it is not an address to publish. Where a partner allow-lists your source address, or DNS points at it, allocate the address yourself and name it — the gateway then egresses from that one:
resource "frostmoln_public_ip" "egress" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.egress.id
}
That address is one of yours: listed among your Public IPs, drawn from the same public IPv4 quota your customer-facing addresses use, and billed as a Public IP. There is no shared-outbound-address option — a VPC egresses through its own gateway, never through an address held in common with other tenants. The converter writes no gateway: connectivity is a stated choice, so that a VPC cannot acquire an outbound path — or a billable public address — because a field was omitted.
INBOUND is per workload, not per VPC. There is no switch that makes a VPC's private addresses routable from the internet: attach a frostmoln_public_ip to the instance that must be reachable, or put a public frostmoln_load_balancer in front of it. An aws_eip in this configuration already converts to a frostmoln_public_ip, so much of the inbound half may already be present.
The same gateway can be created outside Terraform with fm network gateway create.
It adopts rather than duplicates. If the VPC already has a gateway — one the platform attached implicitly because a public IP was associated with an instance in it, or one created outside Terraform later — import that one rather than creating a second; the platform refuses the second with GATEWAY_EXISTS. The resource is one-to-one with its VPC, so the VPC's own id is the import id:
terraform import frostmoln_gateway.main <vpc-id>
aws_internet_gateway_attachment
This resource binds an internet gateway to a VPC, so it disappears with the gateway itself — but the connectivity it stood for does not follow the VPC automatically, which is the part worth reading twice.
OUTBOUND is a separate, explicit resource. A Frostmoln VPC with no gateway is an isolated network: no outbound internet, and — because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does — no name resolution and no managed-service connectivity either. Attach one to the converted VPC:
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
The gateway's source address is drawn by the platform, and you do not choose which one you get, so it is not an address to publish. Where a partner allow-lists your source address, or DNS points at it, allocate the address yourself and name it — the gateway then egresses from that one:
resource "frostmoln_public_ip" "egress" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.egress.id
}
That address is one of yours: listed among your Public IPs, drawn from the same public IPv4 quota your customer-facing addresses use, and billed as a Public IP. There is no shared-outbound-address option — a VPC egresses through its own gateway, never through an address held in common with other tenants. The converter writes no gateway: connectivity is a stated choice, so that a VPC cannot acquire an outbound path — or a billable public address — because a field was omitted.
INBOUND is per workload: attach a frostmoln_public_ip to the instance that must be reachable, or put a public frostmoln_load_balancer in front of it.
The same gateway can be created outside Terraform with fm network gateway create.
It adopts rather than duplicates. If the VPC already has a gateway — one the platform attached implicitly because a public IP was associated with an instance in it, or one created outside Terraform later — import that one rather than creating a second; the platform refuses the second with GATEWAY_EXISTS. The resource is one-to-one with its VPC, so the VPC's own id is the import id:
terraform import frostmoln_gateway.main <vpc-id>
aws_main_route_table_association
Frostmoln has no main route table for a VPC to point at, so this association has nothing to convert to. It is worth being explicit about what that does NOT mean: a Frostmoln VPC has no outbound path until a gateway is attached to it, and a VPC without one is an isolated network — no outbound internet, no name resolution and no managed-service connectivity. See the aws_internet_gateway or aws_nat_gateway entry for what to add, and how to give it a source address you can publish.
aws_nat_gateway
This is not a resource the platform makes unnecessary — it is one you have to replace. A Frostmoln VPC's outbound path is an explicit resource, and a VPC without one is an isolated network: no outbound internet, and — because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does — no name resolution and no managed-service connectivity either. Attach one to the converted VPC:
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
That gateway IS the NAT function this resource performed: every instance in the VPC egresses through it, translated to its source address. The address is drawn by the platform, and you do not choose which one you get — so it is not an address to publish. Where a remote peer allow-lists your source address, or DNS points at it, allocate the address yourself and name it, which is what the NAT gateway's Elastic IP gave you:
resource "frostmoln_public_ip" "egress" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.egress.id
}
That address is one of yours: it appears in your Public IP list, it draws on the same public IPv4 quota your customer-facing Public IPs do, and it is billed as a Public IP. There is no shared-outbound-address option — a VPC egresses through its own gateway, never through an address held in common with other tenants.
The converter does not write the gateway for you, deliberately: connectivity is a stated choice, so that a VPC cannot acquire an outbound path — or a billable public address — because a field was omitted. A VPC that genuinely needs no internet keeps none; leave the block out.
One shape does not carry over at all: a VPC has AT MOST ONE gateway, while this configuration may hold several NAT gateways for the same VPC (typically one per availability zone). A single frostmoln_gateway replaces all of them — that many-to-one collapse is left to you to make rather than performed quietly, because which gateway's behaviour survives is a decision, not a rename. A private NAT gateway (connectivity_type = "private") is not an internet path at all and has no equivalent: there is no transit-gateway concept for it to route to.
The same gateway can be created outside Terraform with fm network gateway create.
It adopts rather than duplicates. If the VPC already has a gateway — one the platform attached implicitly because a public IP was associated with an instance in it, or one created outside Terraform later — import that one rather than creating a second; the platform refuses the second with GATEWAY_EXISTS. The resource is one-to-one with its VPC, so the VPC's own id is the import id:
terraform import frostmoln_gateway.main <vpc-id>
aws_nat_gateway_eip_association
This resource pins a specific Elastic IP as (one of) a NAT gateway's outbound source addresses. Frostmoln expresses the single-address half of that, on the VPC's gateway itself: left to itself the gateway egresses from an address the platform draws, which you do not choose and should not publish, and naming a Public IP you own makes that one the source address instead. Naming it is the analogue of this association, and the answer when a remote peer allow-lists your source IP:
resource "frostmoln_public_ip" "egress" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.egress.id
}
That address is one of yours: listed among your Public IPs, drawn from the same public IPv4 quota your customer-facing addresses use, and billed as a Public IP. You still cannot ask for a PARTICULAR address — the platform allocates it — so an allow-list entry has to be updated once to the address you are given.
Several addresses on one gateway — the reason this resource exists, usually port-exhaustion headroom — has no counterpart at all: a VPC has AT MOST ONE gateway and it carries one source address.
The gateway itself is not created for you; see aws_nat_gateway, and add it with or without the public_ip_id above:
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
The same gateway can be created outside Terraform with fm network gateway create.
It adopts rather than duplicates. If the VPC already has a gateway — one the platform attached implicitly because a public IP was associated with an instance in it, or one created outside Terraform later — import that one rather than creating a second; the platform refuses the second with GATEWAY_EXISTS. The resource is one-to-one with its VPC, so the VPC's own id is the import id:
terraform import frostmoln_gateway.main <vpc-id>
aws_route
Subnet-to-subnet routing within a Frostmoln VPC is automatic, so a route describing it has nothing to convert to.
A default route pointing at an internet or NAT gateway is a different matter: nothing the platform does replaces it. A Frostmoln VPC has no outbound path until a gateway is attached to it, and a VPC without one is an isolated network — no outbound internet, and, because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does, no name resolution and no managed-service connectivity either. See the aws_internet_gateway or aws_nat_gateway entry for what to add, and how to give it a source address you can publish.
aws_route_table
Subnet-to-subnet routing within a Frostmoln VPC is automatic, so the table itself has nothing to convert to. Its default route to an internet or NAT gateway does not survive either, and nothing replaces it implicitly: a Frostmoln VPC has no outbound path until a gateway is attached to it, and a VPC without one is an isolated network — no outbound internet, no name resolution and no managed-service connectivity. See the aws_internet_gateway or aws_nat_gateway entry for what to add, and how to give it a source address you can publish.
aws_route_table_association
Frostmoln subnets route within the VPC without a table to be associated with, so the association has nothing to convert to. What it will not do is give the subnet internet access: a Frostmoln VPC has no outbound path until a gateway is attached to it, and a VPC without one is an isolated network — no outbound internet, no name resolution and no managed-service connectivity. See the aws_internet_gateway or aws_nat_gateway entry for what to add, and how to give it a source address you can publish. Note also that "public subnet" is not a Frostmoln concept: inbound reachability is per workload (a frostmoln_public_ip on the instance, or a public frostmoln_load_balancer), never a property of a subnet.
aws_s3_bucket_acl
This blocks rather than being removed silently: private is already the platform default, but a public-read or cross-account ACL grants access the conversion cannot reproduce, and dropping it without a word would quietly change who can read the data. Customer S3 credentials are denied s3:PutBucketAcl and s3:PutBucketPolicy outright, and frostmoln_bucket exposes no ACL attribute - re-grant access with frostmoln_s3_credential scoped to the bucket.
aws_s3_bucket_lifecycle_configuration
Frostmoln object storage does have lifecycle rules - expiration, noncurrent-version expiration, and aborting incomplete multipart uploads - but frostmoln_bucket exposes no lifecycle attribute, so they are set outside Terraform against the bucket's lifecycle endpoint. Transition rules have no equivalent: a bucket carries a storage class (frostmoln_bucket.storage_class) but objects are not moved between classes on a schedule.
aws_s3_bucket_ownership_controls
Object ownership settings exist on AWS to reconcile ACLs with cross-account writes. Frostmoln has neither: the tenant that owns the bucket owns its objects.
aws_s3_bucket_policy
For the platform API, attach a frostmoln_iam_policy covering the storage operations you need to an api_key, workload_identity, or group. For S3 data-plane access, issue a frostmoln_s3_credential narrowed with allowed_buckets and allowed_actions. A policy that granted PUBLIC access has no equivalent at all - customer credentials are denied s3:PutBucketPolicy outright.
aws_s3_bucket_public_access_block
Frostmoln buckets are private by default and no customer credential may change bucket-level access - s3:PutBucketAcl and s3:PutBucketPolicy are denied outright, and neither frostmoln_bucket nor the portal exposes a bucket ACL. There is nothing to block, so nothing replaces this resource. Access comes from S3 credentials issued to the tenant, which should be narrowed with allowed_buckets.
aws_s3_bucket_server_side_encryption_configuration
Frostmoln stores objects on encrypted disks, so data at rest is always encrypted - there is nothing to switch on. What has no equivalent is key selection: SSE-KMS with a customer-managed key, and bucket keys, cannot be expressed. This blocks rather than being removed silently, because a configuration that named a specific key did so for a key-custody reason that the platform default does not satisfy.
aws_secretsmanager_secret_version
Frostmoln stores the value on the frostmoln_secret (secret_value) and versions it internally — take secret_string from this resource and set it as secret_value on the converted secret. Binary secrets have no equivalent: encode them before storing. Staging labels (AWSCURRENT/AWSPREVIOUS) are platform-managed.
Trademarks. Frostmoln is an independent cloud provider and a competing alternative to Amazon Web Services, Microsoft Azure, Google Cloud, and Oracle Cloud. Frostmoln is not affiliated with, endorsed by, or sponsored by any of them. AWS, Azure, Google Cloud, and Oracle Cloud are trademarks of their respective owners; all references are nominative and for interoperability only.