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.
Provider configuration and tags
Provider block
Each provider "aws" block becomes a provider "frostmoln" block, and an aliased block keeps a literal alias. Region, credentials, role assumption, service endpoints and ignore_tags are not carried. The converted configuration declares frostmoln/frostmoln with version ~> 0.82 and requires frostmoln provider 0.82.0 or newer, so a private registry mirror must carry that version.
Default tags
The provider's default_tags carry onto the frostmoln provider's default_tags, which adds them to every taggable resource the configuration manages. They carry as written, except that: keys in the platform's own namespace (frostmoln_, frostmoln-, __) are removed; keys the frostmoln provider refuses as defaults — the prefixes os_, instance_ and nova_, and the keys request-id, customer-id, project-id, tenant-id, created-at, acl, storage-class, quota-bytes and cors-config, in any letter case — are commented out with a warning, to be set in the tags of the resources that need them; a key or value outside the accepted shape (keys of 1 to 64 bytes made of letters, digits and . _ : -, starting and ending with a letter or digit; values of at most 255 bytes made of letters, digits, spaces and + - . _ : / @ =) is commented out as a blocker; more than 10 tags comments out the whole set as a blocker; a dynamic "default_tags" block, or more than one default_tags block, is not carried (warning); and a provider block removed because another block becomes the same frostmoln configuration does not bring its default_tags (warning when the two differ). A key or value that is not a literal is carried as written, and the frostmoln provider checks it when the configuration is planned.
References to the merged tag set
A reference to a resource's tags_all maps to the converted resource's tags_all where the converted resource type has tags, and stays a blocker where it has none. tags_all holds the resource's own tags and the provider's default tags, plus any tag set outside Terraform. The frostmoln provider does not know tags_all while Terraform plans creating or updating the resource, so such a reference in for_each or count, or in a local value one of them reads, is reported as a blocker.
Tenant default tags
Frostmoln also has tenant default tags, a per-tenant setting of the platform. No source provider setting is tenant-scoped: default_tags apply to the resources of one configuration, and carry onto the frostmoln provider's default_tags, which are configuration-scoped as well. The converter never turns them into tenant default tags. AWS Organizations tag policies (aws_organizations_policy with type TAG_POLICY) are an organisational control with no converter mapping.
Tag colours
AWS tags have no colour. Frostmoln tag colours (set per organization, for display) have no source equivalent: set them after migration with frostmoln_tag_color or in the portal.
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 | images resolve by exact name; recency selection does not apply. |
| owners | Not needed on Frostmoln | there is no account-id concept; the platform image catalog is shared. |
| executable_users | Not needed on Frostmoln | there is no account-id concept; the platform image catalog is shared. |
| filter | Not needed on Frostmoln | image filters have no equivalent; the image name is derived from the name filter (see the synthesized name). |
| name_regex | Not carried over | regex image selection is not supported; set name to the exact image name. |
| include_deprecated | Not carried over | non-active images are hidden from the platform catalog. |
- 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 | generated names are not supported; set an explicit name. |
| 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 | launch configurations have no equivalent; recreate the template as a frostmoln_launch_template and set launch_template_id. |
| mixed_instances_policy | Manual action required | mixed-instance policies are not supported; a scale group uses a single launch template. |
| 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 | a scale group holds a single termination policy (oldest_first, newest_first, or closest_to_next_hour). |
| tag (also matches tags) | Manual action required | convert tag blocks (or the tags list) to the tags map manually; per-tag propagation flags are not supported. |
| availability_zones | Not carried over | the platform picks zones; attach subnets via subnet_ids instead. |
| load_balancers | Manual action required | classic load balancers have no equivalent; attach pools via load_balancer_pool_ids. |
| capacity_rebalance | Not carried over | capacity rebalancing has no equivalent. |
| instance_refresh | Not carried over | instance refresh is not supported; roll instances by updating the launch template. |
| warm_pool | Not carried over | warm pools are not supported. |
| suspended_processes | Not carried over | scaling processes cannot be suspended individually. |
| enabled_metrics | Not carried over | group metrics are platform-managed. |
| metrics_granularity | Not carried over | group metrics are platform-managed. |
| placement_group | Manual action required | placement groups have no equivalent. |
| service_linked_role_arn | Not needed on Frostmoln | Frostmoln has no assumable roles, so there is no service-linked role to name; the platform manages a scale group's own service access. |
| max_instance_lifetime | Not carried over | instance lifetime limits are not supported. |
| instance_maintenance_policy | Not carried over | maintenance policies are not supported. |
| protect_from_scale_in | Not carried over | scale-in protection is not supported. |
| desired_capacity_type | Not carried over | capacity is always an instance count. |
| wait_for_capacity_timeout | Not needed on Frostmoln | creation waits are platform-managed. |
| wait_for_elb_capacity | Not needed on Frostmoln | creation waits are platform-managed. |
| min_elb_capacity | Not needed on Frostmoln | creation waits are platform-managed. |
| force_delete | Not needed on Frostmoln | deletion behavior is platform-defined. |
| force_delete_warm_pool | Not needed on Frostmoln | warm pools are not supported. |
| ignore_failed_scaling_activities | Not needed on Frostmoln | scaling activity handling is platform-managed. |
- 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 | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| storage_tier | Not carried over | snapshot storage tiers have no equivalent. |
| permanent_restore | Not carried over | snapshot archiving has no equivalent. |
| temporary_restore_days | Not carried over | snapshot archiving has no equivalent. |
| outpost_arn | Manual action required | Outposts have no equivalent. |
- 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 | IOPS are set by the volume tier. |
| throughput | Not carried over | throughput is set by the volume tier. |
| kms_key_id | Manual action required | encryption keys are platform-managed. |
| multi_attach_enabled | Manual action required | multi-attach volumes are not supported. |
| final_snapshot | Not carried over | final snapshots on delete are not supported; create a frostmoln_snapshot explicitly. |
| outpost_arn | Manual action required | Outposts have no equivalent. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
- 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 | all public IPs live in the tenant VPC scope; there is no EC2-classic/VPC split. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| address | Manual action required | specific address selection is not supported; the platform allocates the address. |
| public_ipv4_pool | Manual action required | specific address selection is not supported; the platform allocates the address. |
| customer_owned_ipv4_pool | Manual action required | customer-owned IP pools have no equivalent. |
| associate_with_private_ip | Manual action required | associating with a specific private IP is not supported; associate by instance. |
| network_border_group | Not carried over | network border groups have no equivalent. |
| network_interface | Manual action required | network interfaces have no equivalent; associate by instance. |
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 | public IPs re-associate freely. |
| network_interface_id | Manual action required | network interfaces have no equivalent; associations must target an instance. |
| private_ip_address | Manual action required | associating with a specific private IP is not supported. |
| public_ip | Manual action required | reference the EIP resource by allocation_id, not by address. |
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 | security groups are referenced by id, not by name; reference the converted frostmoln_security_group ids in security_groups. |
| 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 | user_data changes always recreate the instance. |
| associate_public_ip_address | Converted | A true value becomes a generated frostmoln_public_ip bound to the instance. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| volume_tags | Not carried over | volume tags belong on the frostmoln_volume resources. |
| private_ip | Not carried over | static private IPs are not supported; the platform assigns one. |
| secondary_private_ips | Manual action required | secondary private IPs are not supported. |
| iam_instance_profile | Manual action required | instances carry no ambient cloud identity — there is no instance profile to attach. Give the instance a frostmoln_api_key (or a frostmoln_s3_credential for bucket access), delivered like any other secret, and grant it what the role granted with a frostmoln_iam_policy attached via frostmoln_iam_policy_attachment. |
| 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 | ephemeral instance-store devices have no equivalent; recreate persistent disks as frostmoln_volume + frostmoln_volume_attachment. |
| network_interface | Manual action required | custom network interfaces are not supported; attach the instance via subnet_id. |
| ipv6_address_count | Manual action required | IPv6 addressing is not supported yet. |
| ipv6_addresses | Manual action required | IPv6 addressing is not supported yet. |
| monitoring | Not needed on Frostmoln | instance monitoring is always on; there is no detailed-monitoring toggle. |
| ebs_optimized | Not needed on Frostmoln | storage connectivity is platform-managed. |
| metadata_options | Not needed on Frostmoln | Frostmoln serves no instance metadata service, so there is nothing to tune. |
| credit_specification | Not needed on Frostmoln | there are no burstable CPU credits; the flavor defines CPU allocation. |
| source_dest_check | Not carried over | Not carried over: there is no per-instance source/destination check. An instance forwards only while a frostmoln_vpc_route names its address as the next hop, and writing that route also lets it source addresses it does not own. Read the cost in the VPC routes documentation first. |
| tenancy | Not carried over | dedicated tenancy is not supported; instances share the platform fleet. |
| host_id | Manual action required | dedicated hosts have no equivalent. |
| host_resource_group_arn | Manual action required | dedicated hosts have no equivalent. |
| placement_group | Manual action required | placement groups have no equivalent. |
| placement_partition_number | Manual action required | placement groups have no equivalent. |
| cpu_options (also matches cpu_core_count, cpu_threads_per_core) | Not carried over | CPU topology is defined by the flavor. |
| hibernation | Not carried over | hibernation is not supported. |
| disable_api_termination | Not carried over | termination protection is not supported. |
| disable_api_stop | Not carried over | stop protection is not supported. |
| instance_initiated_shutdown_behavior | Not carried over | shutdown behavior is platform-defined. |
| instance_market_options | Manual action required | spot/market instances have no equivalent; instances are always on-demand. |
| capacity_reservation_specification | Not carried over | capacity reservations are not supported. |
| get_password_data | Not carried over | password data retrieval is not supported; use SSH keys. |
| launch_template | Manual action required | launch-template-driven instances are not supported; set the instance attributes directly (frostmoln_launch_template pairs with scale groups). |
| maintenance_options | Not carried over | maintenance windows are platform-managed. |
| private_dns_name_options | Not carried over | instance DNS records are platform-managed. |
| enclave_options | Manual action required | Nitro enclaves have no equivalent. |
- 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 | Generated key names are not supported; set an explicit name. |
| public_key | Mapped to public_key | |
| tags | Not carried over | frostmoln_ssh_key has no tags. |
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 | generated names are not supported; set an explicit name. |
| description | Not carried over | launch templates have no description. |
| 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 | security groups are referenced by id, not by name; reference the converted frostmoln_security_group ids in security_group_ids. |
| user_data | Converted | AWS launch-template user data is base64; frostmoln_launch_template takes plain text. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| tag_specifications | Manual action required | per-resource tag propagation is not supported; set tags on the created resources. |
| default_version | Not needed on Frostmoln | launch templates are not versioned. |
| update_default_version | Not needed on Frostmoln | launch templates are not versioned. |
| block_device_mappings | Manual action required | A volume split arrives in a later release. |
| network_interfaces | Manual action required | custom network interfaces are not supported; scale groups attach instances via subnet_ids. |
| iam_instance_profile | Manual action required | instances carry no ambient cloud identity — there is no instance profile to attach. Give the instance a frostmoln_api_key (or a frostmoln_s3_credential for bucket access), delivered like any other secret, and grant it what the role granted with a frostmoln_iam_policy attached via frostmoln_iam_policy_attachment. |
| instance_market_options | Manual action required | spot/market instances have no equivalent; instances are always on-demand. |
| instance_requirements | Manual action required | attribute-based instance selection is not supported; set an explicit flavor. |
| placement | Manual action required | placement groups have no equivalent. |
| monitoring | Not needed on Frostmoln | instance monitoring is always on; there is no detailed-monitoring toggle. |
| ebs_optimized | Not needed on Frostmoln | storage connectivity is platform-managed. |
| metadata_options | Not needed on Frostmoln | Frostmoln serves no instance metadata service, so there is nothing to tune. |
| credit_specification | Not needed on Frostmoln | there are no burstable CPU credits; the flavor defines CPU allocation. |
| cpu_options | Not carried over | CPU topology is defined by the flavor. |
| kernel_id | Not carried over | custom kernels are not supported. |
| ram_disk_id | Not carried over | custom RAM disks are not supported. |
| disable_api_stop | Not carried over | stop protection is not supported. |
| disable_api_termination | Not carried over | termination protection is not supported. |
| instance_initiated_shutdown_behavior | Not carried over | shutdown behavior is platform-defined. |
| hibernation_options | Not carried over | hibernation is not supported. |
| elastic_gpu_specifications (retired by the provider) | Manual action required | GPU accelerators have no equivalent yet. |
| elastic_inference_accelerator (retired by the provider) | Manual action required | inference accelerators have no equivalent. |
| enclave_options | Manual action required | Nitro enclaves have no equivalent. |
| license_specification | Not carried over | license configurations have no equivalent. |
| maintenance_options | Not carried over | maintenance windows are platform-managed. |
| private_dns_name_options | Not carried over | instance DNS records are platform-managed. |
| capacity_reservation_specification | Not carried over | capacity reservations are not supported. |
- 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 type l7/l4.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| name_prefix | Manual action required | generated names are not supported; set an explicit name. |
| 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 type | |
| subnets | Converted to subnet_id | Frostmoln load balancers attach to a single subnet - keep one subnet and recreate the rest as separate load balancers. |
| subnet_mapping | Manual action required | static address mappings are not supported; use public_ip_id for a public address. |
| security_groups | Not carried over | access control moves to listener allowed_cidrs. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| enable_deletion_protection | Not carried over | deletion protection is not supported. |
| access_logs | Manual action required | load-balancer access logs are not available. |
| connection_logs | Manual action required | load-balancer connection logs are not available. |
| idle_timeout | Not carried over | idle timeouts are platform-managed. |
| enable_http2 | Not carried over | HTTP/2 negotiation is platform-managed. |
| enable_cross_zone_load_balancing | Not needed on Frostmoln | the platform runs a single zone per load balancer. |
| ip_address_type | Not carried over | load balancers are IPv4 today. |
| drop_invalid_header_fields | Not carried over | header handling is platform-managed. |
| preserve_host_header | Not carried over | header handling is platform-managed. |
| xff_header_processing_mode | Not carried over | header handling is platform-managed. |
| desync_mitigation_mode | Not carried over | desync mitigation is platform-managed. |
| enable_waf_fail_open | Not carried over | Frostmoln's Web Application Firewall belongs to the Application Gateway, a separate offer from the load balancer — set fail_mode on a gateway-scoped frostmoln_appgw_waf_policy and publish it with a frostmoln_appgw_waf_policy_publication, because the setting is authored rather than enforced until it is published. |
| dns_record_client_routing_policy | Not carried over | DNS routing policies are not supported. |
| enable_tls_version_and_cipher_suite_headers | Not carried over | header handling is platform-managed. |
| enable_zonal_shift | Not carried over | zonal shift has no equivalent. |
| client_keep_alive | Not carried over | keep-alive tuning is platform-managed. |
| customer_owned_ipv4_pool | Manual action required | customer-owned IP pools have no equivalent. |
| enforce_security_group_inbound_rules_on_private_link_traffic | Not carried over | there is no PrivateLink concept. |
- 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 | TLS policies are platform-managed. |
| certificate_arn | Manual action required | upload the certificate to the platform and set tls_certificate_id. |
| alpn_policy | Not carried over | ALPN negotiation is platform-managed. |
| mutual_authentication | Manual action required | mutual TLS is not supported. |
| tcp_idle_timeout_seconds | Not carried over | idle timeouts are platform-managed. |
| tags | Not carried over | frostmoln_lb_listener carries no tags; tag the load balancer instead. |
- 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 an l4 load balancer only supports source_ip_port, so change lb_algorithm when attaching this pool to an l4 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 | generated names are not supported; set an explicit name. |
| protocol | Converted | |
| port | Not carried over | member ports are set per frostmoln_lb_member protocol_port. |
| vpc_id | Not needed on Frostmoln | the pool inherits networking from its load balancer. |
| target_type | Not needed on Frostmoln | pool members are addresses; there is no target-type concept. |
| 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 | anomaly mitigation has no equivalent. |
| load_balancing_cross_zone_enabled | Not needed on Frostmoln | the platform runs a single zone per load balancer. |
| proxy_protocol_v2 | Converted to proxy_protocol | |
| deregistration_delay | Not carried over | member draining is platform-managed. |
| slow_start | Not carried over | slow start is not supported. |
| preserve_client_ip | Not carried over | client-IP preservation is platform-managed. |
| connection_termination | Not carried over | connection termination on deregister is platform-managed. |
| lambda_multi_value_headers_enabled | Manual action required | Lambda targets have no equivalent. |
| ip_address_type | Not carried over | pools are IPv4 today. |
| target_failover | Not carried over | target failover has no equivalent. |
| target_health_state | Not carried over | health-state handling is platform-managed. |
| target_group_health | Not carried over | group-health thresholds have no equivalent. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
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 | max_retries covers the retry count; a separate unhealthy threshold is not supported. |
| matcher | Mapped to expected_codes | |
| port | Not carried over | health checks run against each member's protocol_port. |
| enabled | Not carried over | monitors are always enabled; remove the monitor resource to disable checks. |
- 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 platform picks zones. |
- The converter adds
load_balancer_idautomatically. frostmoln_lb_member requires load_balancer_id; set it to the converted load balancer.
aws_route → frostmoln_vpc_route — partially supported
a route to an appliance in the VPC becomes a frostmoln_vpc_route with its destination carried over and vpc_id plus the next-hop ADDRESS left as placeholders to fill in; a route to a gateway, NAT gateway, transit gateway, peering connection or endpoint is left unconverted (a specific destination out the internet gateway is rewritten by hand as next_hop = internet), a prefix-list destination is left unconverted, and an IPv6 destination converts like an IPv4 one except for an IPv6 default route, which does not.
A Frostmoln VPC has ONE route set and it belongs to the VPC, not to a table you associate with subnets — so a converted route applies to every instance in the VPC, whichever subnets its source table was associated with. Check for a route whose reach that WIDENS before you apply.
Subnet-to-subnet routing within the VPC is automatic and cannot be overridden: a destination that is, or falls inside, a subnet attached to the VPC is REFUSED, because that subnet already delivers it directly. An east-west route that sends one subnet's traffic to a firewall or inspection appliance therefore has no counterpart here and cannot be recreated — do not read it as redundant. Enforce east-west policy with security groups instead.
Two values cannot be carried over and are emitted as FM-TODO placeholders:
- vpc_id, because route_table_id names a route table and the platform has none. Set it to the converted frostmoln_vpc.
- next_hop, because a Frostmoln next hop is an IP ADDRESS on a subnet attached to the VPC (or the reserved token
internet), never a resource id. An appliance route — network_interface_id or instance_id — therefore converts with its destination intact and its next hop left for you: set it to the appliance's address on a subnet in the VPC. The route is refused at apply time if that address is not reachable from one.
A route pointing at a gateway, a transit gateway, a peering connection, a VPC endpoint, or a carrier or local gateway is left UNCONVERTED rather than converted with a placeholder: a route that quietly sends the same traffic somewhere else is worse than no route, and the converter cannot always tell from the source which of them a gateway_id names.
ONE OF THEM DOES HAVE A COUNTERPART, and it is the one a forced tunnel needs. A route sending a SPECIFIC destination out the internet gateway is written here as a frostmoln_vpc_route with next_hop = "internet" — a reserved token meaning "out this VPC's own gateway", not an address. That is how you keep a VPN appliance's own tunnel working underneath a default route: without a more specific route for the appliance's remote peer, its encrypted packets match the default route and loop back to it. Because a route is matched on its destination only, that exception takes every instance in the VPC off the tunnel for the peer's address, not just the appliance. Rewrite such a route by hand; the converter will not guess it for you.
A DEFAULT route out the internet gateway is different: there is nothing to write, because the VPC's own gateway already provides it, and writing one is refused. But the gateway itself is not implied — a Frostmoln VPC has no outbound path until a frostmoln_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 reach to that control plane either. (A managed database, cache or broker deployed INTO the VPC still answers on its private address — that traffic never crosses the gateway — but reaching it by name does need DNS.) 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.
A default route (0.0.0.0/0) IS accepted with an in-VPC next hop — an appliance address — and it captures ALL egress from the VPC. Public IPs on instances in that VPC stop serving while it exists, because the reply is routed by this same set and its destination is the internet client; the platform DNS resolver and the managed-service control plane keep working, because they ride routes more specific than a default one. It also counts as TWO against the VPC's route limit. A default route pointing at internet is refused instead: that is the route the VPC's own gateway already provides. A route naming an INSTANCE address lets that instance send with source addresses it does not own: every subnet attached to the VPC, plus the destination of every route pointing at that address -- with a default route, any address at all. Security group rules keyed on a source address stop constraining it, and it can claim another instance's address on the subnet. That is what makes the appliance forward at all, and it is granted automatically with no way to narrow it, so keep such an instance a dedicated appliance and put anything that must be protected from it in another VPC.
| Attribute | Outcome | Notes |
|---|---|---|
| route_table_id | Not carried over | There are no route tables; vpc_id is emitted as a placeholder for you to point at the converted frostmoln_vpc. |
| region | Not needed on Frostmoln | the platform is single-region; the default region applies. |
| destination_cidr_block | Converted to destination | Carried over. A prefix with host bits set is masked (203.0.113.5/24 -> 203.0.113.0/24), which is the form the platform accepts; a LITERAL default route is flagged, because it captures all egress from the VPC (one built from a variable cannot be read, so it is not); a default-route half (0.0.0.0/1, 128.0.0.0/1) is refused, because those are how the platform stores a default route internally. |
| destination_ipv6_cidr_block | Converted to destination | Carried over like an IPv4 destination — an IPv6 route is legal with an IPv6 next hop on a subnet attached to the VPC, so set next_hop to one. An IPv6 DEFAULT route (::/0) is the exception: it is not offered, and it leaves the whole route unconverted. |
| destination_prefix_list_id | Manual action required | Left unconverted: prefix lists have no equivalent. Write the ranges the list holds as individual routes. |
| network_interface_id | Not carried over | A next hop is an IP ADDRESS, not a resource id, so next_hop is emitted as a placeholder: set it to the appliance's address on a subnet attached to the VPC. |
| instance_id | Not carried over | A next hop is an IP ADDRESS, not a resource id, so next_hop is emitted as a placeholder: set it to the instance's address on a subnet attached to the VPC. |
| gateway_id | Manual action required | Left unconverted because the three kinds of gateway this attribute carries convert differently. An internet gateway with a SPECIFIC destination becomes next_hop = internet — that is how the exception route a forced tunnel needs is written. A 0.0.0.0/0 to an internet gateway needs no route at all: the VPC's frostmoln_gateway already provides it, and writing one is refused. A VPN or local gateway has no equivalent. |
| nat_gateway_id | Manual action required | Left unconverted. Outbound comes from the VPC's frostmoln_gateway, which already carries the default route; a specific destination that should leave through it is written as next_hop = internet. |
| egress_only_gateway_id | Manual action required | Left unconverted: this is an IPv6-only construct and the platform does not offer customer IPv6 routing yet. |
| transit_gateway_id | Manual action required | Left unconverted: transit gateways have no equivalent. |
| vpc_peering_connection_id | Manual action required | Left unconverted: VPC peering has no equivalent — place workloads that must communicate in the same VPC. |
| vpc_endpoint_id | Manual action required | Left unconverted: VPC endpoints have no equivalent. |
| carrier_gateway_id | Manual action required | Left unconverted: carrier gateways have no equivalent. |
| local_gateway_id | Manual action required | Left unconverted: Outposts local gateways have no equivalent. |
| core_network_arn | Manual action required | Left unconverted: Cloud WAN core networks have no equivalent. |
| odb_network_arn | Manual action required | Left unconverted: Oracle Database@AWS networks have no equivalent. |
- The converter adds
vpc_idautomatically. a frostmoln_vpc_route belongs to a VPC rather than to a route table; set vpc_id to the converted frostmoln_vpc. - The converter adds
next_hopautomatically. a next hop is an IP address on a subnet attached to the VPC, or the tokeninternet(which needs the VPC to have a frostmoln_gateway); set next_hop to the address traffic for this destination should go to.
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 | alias records have no equivalent; the record is converted to an explicit record with FM-TODO placeholders - fill in the value the alias resolved to (the commented-out alias block shows what it pointed at) and the TTL. |
| weighted_routing_policy | Manual action required | routing policies are not supported. |
| latency_routing_policy | Manual action required | routing policies are not supported. |
| failover_routing_policy | Manual action required | routing policies are not supported. |
| geolocation_routing_policy | Manual action required | routing policies are not supported. |
| geoproximity_routing_policy | Manual action required | routing policies are not supported. |
| cidr_routing_policy | Manual action required | routing policies are not supported. |
| multivalue_answer_routing_policy | Manual action required | routing policies are not supported. |
| set_identifier | Manual action required | routing policies are not supported. |
| health_check_id | Manual action required | DNS health checks are not supported. |
| allow_overwrite | Not needed on Frostmoln | records are managed exclusively through Terraform; there is no overwrite concept. |
- 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 | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| vpc | Manual action required | private hosted zones are not supported; only public zones convert. |
| force_destroy | Not needed on Frostmoln | zones are deleted with their records. |
| delegation_set_id | Not carried over | delegation sets are platform-managed. |
- 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); CORS and lifecycle rules are separate Frostmoln resources you recreate alongside it, while ACLs, policies, website hosting, 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 and CORS are not attributes of frostmoln_bucket: they are their own resources, frostmoln_bucket_lifecycle_configuration and frostmoln_bucket_cors_configuration, each replacing its bucket's document whole. The converter does not generate them, so recreate them yourself.
| Attribute | Outcome | Notes |
|---|---|---|
| bucket | Mapped to name | |
| bucket_prefix | Manual action required | generated names are not supported; set an explicit name. |
| region | Converted | Frostmoln is single-region today; the platform default region applies. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| force_destroy | Not needed on Frostmoln | bucket deletion behavior is platform-defined. |
| acl | Manual action required | ACLs cannot be set from Terraform; buckets are private by default - re-grant access with frostmoln_s3_credential narrowed to the bucket. |
| grant | Manual action required | ACL grants are not supported; buckets are private - re-grant access with S3 credentials scoped to the bucket. |
| policy | Manual action required | bucket policies are not supported; re-create access rules with S3 credentials scoped to the bucket. |
| website | Manual action required | static-website hosting is not available. |
| cors_rule | Manual action required | a bucket's CORS configuration is a separate resource on Frostmoln and is not generated here — recreate these rules as a frostmoln_bucket_cors_configuration for the bucket. It replaces the bucket's CORS document WHOLE, and every new bucket already carries a rule Frostmoln added for the customer portal's origin, so a configuration that declares only the origins converted from here silently removes it and the portal's object browser stops working for that bucket. That default is applied at bucket creation only, so nothing puts it back: read the bucket's current CORS before taking it over and re-declare what is actually there. |
| lifecycle_rule | Manual action required | a bucket's lifecycle configuration is a separate resource on Frostmoln and is not generated here — recreate the expiration, noncurrent-version expiration and abort-incomplete-multipart rules as a frostmoln_bucket_lifecycle_configuration. Storage-class transition rules have no counterpart: a bucket carries a storage class, but objects are not moved between classes on a schedule. |
| versioning | Manual action required | set the versioning attribute on frostmoln_bucket instead (an aws_s3_bucket_versioning resource merges automatically). |
| logging | Not carried over | bucket access logging is not yet configurable. |
| replication_configuration | Manual action required | cross-region replication is not available. |
| server_side_encryption_configuration | Manual action required | object data is encrypted at rest unconditionally, but there is no per-bucket setting and no customer-managed key; re-check the requirement that named this key. |
| object_lock_configuration | Manual action required | object lock is not available. |
| object_lock_enabled | Manual action required | object lock is not available. |
| acceleration_status | Not needed on Frostmoln | there is no transfer-acceleration concept. |
| request_payer | Not needed on Frostmoln | there is no requester-pays billing concept. |
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 | there is no account-id concept. |
| mfa | Not carried over | MFA delete is not supported. |
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 | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| name_prefix | Manual action required | generated names are not supported; set an explicit name. |
| kms_key_id | Not needed on Frostmoln | secrets are always encrypted at rest with a platform-managed key; there is no key to select. |
| policy | Manual action required | resource policies are not supported; grant access with a frostmoln_iam_policy attached to the api_key, workload_identity, or group that needs the secret. |
| replica | Not needed on Frostmoln | data is stored in the single EU region; there is nothing to replicate to. |
| force_overwrite_replica_secret | Not needed on Frostmoln | there are no replicas. |
- 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 (the platform adds one IPv4 and one IPv6 allow-any egress rule to every new group and 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 the platform 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; 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 | generated names are not supported; set an explicit name. |
| description | Converted | The description is carried to the security group's description. One longer than the platform's 1024-character limit is refused with a blocker rather than converted to configuration that fails when applied. |
| vpc_id | Mapped to vpc_id | |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| revoke_rules_on_delete | Not needed on Frostmoln | rule cleanup on delete is platform-managed. |
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 | the block's ipv6_cidr_blocks entries are IPv6 remotes, and a frostmoln_security_group_rule has no ether_type field — every rule the platform creates is IPv4, so no rule was generated for them. The block's cidr_blocks entries still converted: this security group is missing exactly the IPv6 half of what the source declared. Restrict those remotes to IPv4 CIDRs, or leave them out until the platform supports IPv6 security-group rules — do NOT translate an IPv6 range to an IPv4 one, it selects different hosts. (An inline block whose ONLY remote is ipv6_cidr_blocks generates no rules at all and blocks in full; the standalone aws_security_group_rule resource blocks the whole rule for the same reason.) |
| prefix_list_ids | Manual action required | prefix lists have no equivalent; expand them into CIDR rules. |
- 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 | a rule holds a single remote_cidr; create one frostmoln_security_group_rule per 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 | the rule's remotes are IPv6, and a frostmoln_security_group_rule has no ether_type field — every rule the platform creates is IPv4, so this rule cannot be expressed and was left unconverted rather than emitted as a rule that is rejected when it is applied. Restrict the remote to an IPv4 CIDR, or leave the rule out until the platform supports IPv6 security-group rules — do NOT translate an IPv6 range to an IPv4 one, it selects different hosts. |
| prefix_list_ids | Manual action required | prefix lists have no equivalent; expand them into CIDR rules. |
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 | CIDR-based lookup is not supported; look the subnet up by id or name. |
| availability_zone | Manual action required | zone-based lookup is not supported; look the subnet up by id or name. |
| availability_zone_id | Manual action required | zone-based lookup is not supported; look the subnet up by id or name. |
| default_for_az | Manual action required | there is no default-for-AZ lookup; look the subnet up by id or name. |
| state | Manual action required | state-based lookup is not supported; look the subnet up by id or name. |
| tags | Manual action required | tag-based lookup is not supported; look the subnet up by id or name. |
| filter | Manual action required | filter-based lookup is not supported; look the subnet up by id or name. |
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 | the platform picks the zone; set zone manually to pin one. |
| map_public_ip_on_launch | Not needed on Frostmoln | inbound reachability is per workload (a public IP on the instance, or a load balancer), not subnet-level auto-assignment; outbound is the VPC's gateway (frostmoln_gateway), also never a subnet property. |
| tags | Converted | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| assign_ipv6_address_on_creation | Manual action required | IPv6 subnets are not supported yet. |
| ipv6_cidr_block | Manual action required | IPv6 subnets are not supported yet. |
| ipv6_native | Manual action required | IPv6 subnets are not supported yet. |
| enable_dns64 | Manual action required | IPv6 subnets are not supported yet. |
| enable_resource_name_dns_a_record_on_launch | Not carried over | instance DNS records are platform-managed. |
| enable_resource_name_dns_aaaa_record_on_launch | Not carried over | instance DNS records are platform-managed. |
| private_dns_hostname_type_on_launch | Not carried over | instance DNS records are platform-managed. |
| customer_owned_ipv4_pool | Manual action required | customer-owned IP pools have no equivalent. |
| map_customer_owned_ip_on_launch | Manual action required | customer-owned IP pools have no equivalent. |
| outpost_arn | Manual action required | Outposts have no equivalent. |
- 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 | detach behavior is platform-managed. |
| skip_destroy | Not carried over | attachments are always detached on destroy. |
| stop_instance_before_detaching | Not carried over | detach behavior is platform-managed. |
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 | CIDR-based lookup is not supported; look the VPC up by id or name. |
| dhcp_options_id | Manual action required | DHCP-options lookup is not supported; look the VPC up by id or name. |
| default | Manual action required | there is no default-VPC lookup; look the VPC up by id or name. |
| state | Manual action required | state-based lookup is not supported; look the VPC up by id or name. |
| tags | Manual action required | tag-based lookup is not supported; look the VPC up by id or name. |
| filter | Manual action required | filter-based lookup is not supported; look the VPC up by id or name. |
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 control plane, because those are reached over routes that exist only while the egress path does (a managed database, cache or broker deployed INTO the VPC still answers on its private address; reaching it by name needs DNS). 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 | |
| tags_all | Not carried over | tags_all is computed, not configured: tags carry in tags, the provider-level default_tags carry onto the frostmoln provider's default_tags where the frostmoln provider accepts them as defaults, and the converted resource's tags_all holds the merged set plus any tag set outside Terraform. |
| enable_dns_support | Not needed on Frostmoln | platform DNS is always on |
| enable_dns_hostnames | Not needed on Frostmoln | platform DNS is always on |
| instance_tenancy | Not carried over | there is no dedicated-tenancy concept; all VPCs share the platform fleet. |
| enable_network_address_usage_metrics | Not carried over | address-usage metrics are not exposed per VPC. |
| ipv4_ipam_pool_id | Manual action required | no IPAM/IPv6 support yet. |
| ipv4_netmask_length | Manual action required | no IPAM/IPv6 support yet. |
| ipv6_cidr_block | Manual action required | no IPAM/IPv6 support yet. |
| ipv6_ipam_pool_id | Manual action required | no IPAM/IPv6 support yet. |
| ipv6_netmask_length | Manual action required | no IPAM/IPv6 support yet. |
| ipv6_cidr_block_network_border_group | Manual action required | no IPAM/IPv6 support yet. |
| assign_generated_ipv6_cidr_block | Manual action required | no IPAM/IPv6 support yet. |
- The converter adds
nameautomatically. frostmoln_vpc requires a name; it is taken from the Name tag or the resource address.
Resources the converter does not convert
| 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 | There is no main route table to point at: a Frostmoln VPC has ONE route set that already applies to the whole VPC, so this association is removed — and it carries no VPC-wide default route to the internet, which 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_table | There is no route-table object: a Frostmoln VPC has ONE route set, held on the VPC itself, so the table is removed — its individual routes are convertible (see aws_route), but routes written INLINE in this block are not, and the internet default route it usually carries is not replaced. |
| aws_route_table_association | There is nothing to associate: a Frostmoln VPC has ONE route set that applies to every subnet in it, so the association is removed and the routes of every associated table merge into that one set. |
| 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 | Lifecycle rules are a frostmoln_bucket_lifecycle_configuration, but this resource is not converted automatically - rewrite it, because the rule vocabularies differ and a wrong guess here deletes objects. |
| 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. |
| aws_wafv2_web_acl | Frostmoln has a Web Application Firewall, but it is part of an Application Gateway rather than a standalone resource, so a web ACL does not convert on its own — recreate it as a frostmoln_appgw_waf_policy on the gateway that fronts the same traffic. |
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 reach to that control plane 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 reach to that control plane 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 reach to that control plane 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
A Frostmoln VPC's single route set already is what a main route table is for: the fallback that applies to everything in the VPC. So the association has nothing to convert into, and the routes themselves still convert — see the aws_route entry.
Because there is only one set, ROUTES FROM EVERY TABLE IN THIS VPC MERGE into it, main and non-main alike. Look for the same destination appearing in more than one table with a different target — only one of them can survive, and the platform refuses the second as a duplicate.
It is worth being explicit about what none of this means: 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 control plane. (A managed database, cache or broker deployed INTO the VPC still answers on its private address; reaching it by name needs DNS.) 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 reach to that control plane 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_table
Static routes themselves DO convert — one frostmoln_vpc_route per route, on the VPC. What has no counterpart is the TABLE: a Frostmoln VPC has a single route set, and it cannot be associated with individual subnets. Two consequences are worth checking before you migrate:
- ROUTES FROM DIFFERENT TABLES MERGE. If this VPC has several route tables associated with different subnets, every route in them lands in one set and applies to every instance in the VPC. Look for the same destination appearing in more than one table with a different target — only one of them can survive, and the platform refuses the second as a duplicate.
- ROUTES WRITTEN INLINE IN THIS BLOCK ARE NOT CONVERTED. Only a standalone aws_route resource converts; a
route { ... }block inside the table is removed with it. Rewrite each one as a frostmoln_vpc_route on the converted frostmoln_vpc.
Subnet-to-subnet routing within a Frostmoln VPC is automatic and cannot be overridden: a destination inside a subnet attached to the VPC is REFUSED. An east-west route sending one subnet's traffic to a firewall appliance has no counterpart and cannot be recreated — do not read it as redundant; enforce east-west policy with security groups.
A 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 control plane. (A managed database, cache or broker deployed INTO the VPC still answers on its private address; reaching it by name needs DNS.) 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 routes are held on the VPC and apply to all of it, so there is no per-subnet binding for this association to convert into. That is the thing to check before migrating: ROUTES FROM TABLES ASSOCIATED WITH DIFFERENT SUBNETS MERGE into a single set, and the distinction between them is lost. Look for the same destination appearing in more than one table with a different target — only one of them can survive, and the platform refuses the second as a duplicate.
The individual routes still convert; see the aws_route entry. What the association 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 control plane. (A managed database, cache or broker deployed INTO the VPC still answers on its private address; reaching it by name needs DNS.) 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
Recreate the rules as a frostmoln_bucket_lifecycle_configuration naming the bucket: expiration, noncurrent-version expiration and aborting incomplete multipart uploads all carry over, scoped by prefix. Transition rules do NOT: a bucket carries a storage class (frostmoln_bucket.storage_class) but objects are not moved between classes on a schedule, and there is no per-object-tag filter. The resource replaces the bucket's lifecycle document whole, so declare every rule you want to keep - and re-scope by prefix any rule that relied on a tag or size filter, because a rule that expires objects and loses its filter deletes everything in the bucket.
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.
aws_wafv2_web_acl
This entry exists so the firewall is REPORTED rather than silently dropped. A web ACL is usually the only thing standing between the internet and an application, and a conversion that says nothing about it leaves the customer believing their protection came across.
What it maps onto:
- the ACL itself is a frostmoln_appgw_waf_policy on a frostmoln_application_gateway,
gateway-scoped for the whole gateway oroverlay-scoped for one listener or one route; - AWS managed rule groups are the platform's own managed ruleset, which every gateway-scoped policy carries. It is tuned with paranoia_level and anomaly_score_threshold rather than selected group by group, and its version is read (managed_ruleset_version), not written;
- each of your own rule statements is a frostmoln_appgw_waf_rule with kind = "builder" and a builder_json condition set;
- a rule you switch off inside a managed group is a frostmoln_appgw_waf_rule with kind = "managedOverride", or — better where it is only a false positive on one field — a frostmoln_appgw_waf_exclusion, which narrows the rule instead of disabling it everywhere;
- the ACL's association with a load balancer is a frostmoln_appgw_waf_policy_attachment.
What does not map: rate-based statements (per-source rate limiting is rate_limit_rps and rate_limit_burst on a frostmoln_appgw_listener, not a WAF rule), CAPTCHA and challenge actions, labels, and the CLOUDFRONT scope.
THE PART THAT IS EASY TO GET WRONG. A frostmoln_appgw_waf_policy and its rules are AUTHORED, not enforced. What the gateway inspects with is the last PUBLISHED version, so a policy written without a frostmoln_appgw_waf_policy_publication inspects nothing, while terraform apply succeeds and the plan looks complete. And a published version still only reaches the appliance on the gateway's next frostmoln_appgw_config_apply. Write all of them, or the firewall is a configuration that governs no traffic.
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.