Skip to content

Migrating Google Cloud Terraform to Frostmoln

To run a conversion, see the migration guide.

This matrix lists how the converter handles each supported resource type and attribute.

google_compute_address → frostmoln_public_ip — partially supported

External addresses map to frostmoln_public_ip; a specific address cannot be requested — the platform allocates one.

Only an EXTERNAL address maps to a public IP; an INTERNAL address has no equivalent and BLOCKS the conversion (mapping it to an external public IP would be silently wrong). A specific reserved address (the address argument) cannot be requested. GCP labels become frostmoln tags.

AttributeOutcomeNotes
address_typeConvertedEXTERNAL (or unset) becomes a public IP; INTERNAL blocks the conversion.
labelsConverted to tagsGCP labels become frostmoln tags.
addressManual action required
regionConvertedFrostmoln is single-region today; the platform default region applies.
network_tierNot carried over
purposeNot carried over
subnetworkNot needed on Frostmoln
prefix_lengthManual action required
ip_versionManual action required
nameNot carried over
descriptionNot carried over
projectNot needed on Frostmoln

google_compute_attached_disk → frostmoln_volume_attachment — supported

Attached disks map directly to frostmoln_volume_attachment; the disk becomes volume_id and the instance becomes instance_id.

device_name becomes device_path. The attachment mode (READ_ONLY / READ_WRITE) is platform-managed and dropped.

AttributeOutcomeNotes
diskMapped to volume_id
instanceMapped to instance_id
device_nameMapped to device_path
modeNot carried over
zoneNot needed on Frostmoln
projectNot needed on Frostmoln

google_compute_disk → frostmoln_volume — partially supported

Persistent disks map to frostmoln_volume; the disk type (pd-ssd/pd-balanced) is dropped (the platform's volume tier applies) and IOPS/throughput are set by the tier.

Volume tiers are platform-defined — pick a volume_type from the volume tiers catalog (frostmoln_volume_tiers data source) after the conversion. A disk created from a snapshot keeps snapshot as snapshot_id (a direct google_compute_snapshot reference is rewritten). A disk created from an image has no equivalent — boot instances from a frostmoln_image instead. A required volume name is the disk name.

AttributeOutcomeNotes
nameMapped to name
descriptionMapped to description
sizeMapped to size_gb
typeNot carried over
zoneConvertedThe platform picks the zone; set zone to a zone id to pin one.
snapshotConverted to snapshot_idA direct google_compute_snapshot reference is rewritten to the converted frostmoln_snapshot id; otherwise set snapshot_id manually.
imageManual action required
labelsConverted to tagsGCP labels become frostmoln tags.
physical_block_size_bytesNot carried over
provisioned_iopsNot carried over
provisioned_throughputNot carried over
disk_encryption_keyManual action required
source_snapshot_encryption_keyManual action required
source_image_encryption_keyManual action required
guest_os_featuresNot carried over
interface (retired by the provider)Not carried over
projectNot needed on Frostmoln

google_compute_firewall → frostmoln_security_group — partially supported

Firewall rules become a frostmoln_security_group plus one frostmoln_security_group_rule per allow protocol × port × remote CIDR. This is the key GCP semantic mismatch: GCP firewalls are network-scoped and select instances by target_tags, whereas Frostmoln security groups attach to instances directly.

A DENY rule has no equivalent and BLOCKS the whole firewall — the platform is allow-only, so a converted deny would OPEN the traffic it denied. A DISABLED firewall also blocks (converting an inactive allow to active rules would widen access). A dynamic "allow" block cannot be enumerated — its contents are unreadable at conversion time, so NO rule is generated for anything it declares, and the refusal is reported as a blocker. The firewall's STATIC allow blocks still convert; if a dynamic block is the only source of allow rules the whole firewall blocks. A dynamic "deny" blocks the firewall exactly as a static deny does. source_ranges (ingress) / destination_ranges (egress) become remote_cidr; a firewall must use static CIDR ranges to convert. target_tags/target_service_accounts select instances by tag — the converter does NOT guess instance membership; it emits a review action telling you to attach the generated security group to those instances (frostmoln_instance.security_groups). NOTE THE SEVERITY: that loss is reported as a WARNING review action and the conversion still succeeds, so fm terraform convert exits 0 — the generated security group is attached to NOTHING until you attach it, and no blocker stops you applying it. The same holds for a tag-scoped SOURCE alongside explicit ranges. A firewall that declares its allow rules in ATTRIBUTE form (allow = [...]) blocks, because the converter reads the block form only. Tag-scoped SOURCES (source_tags/source_service_accounts) with no source_ranges block (dropping them would open the rule to all sources). Priority is dropped (allow-only rules are additive and order-independent). EGRESS DEFAULTS MATCH THE SOURCE - DO NOT "FIX" THEM: every Frostmoln security group is created with allow-all egress (Neutron adds one IPv4 and one IPv6 allow-any egress rule to every new group, and Frostmoln removes neither), and converted egress rules ADD to those defaults rather than replacing them, but GCP already permits all egress through an implied rule at priority 65535 and narrows it only with a DENY egress rule - a deny firewall, which blocks this conversion outright, or a firewall-policy rule (google_compute_firewall_policy_rule and friends), which this converter does not convert at all. An ALLOW EGRESS firewall with destination_ranges narrows nothing on its own, so for every firewall that converts, allow-all egress MATCHES the posture the source had. If the source configuration did contain a deny-egress firewall or a firewall-policy egress rule, its restriction is absent from the output entirely - re-express it as the allow-list the converted group needs, then delete the two defaults. Otherwise do NOT delete the two default egress rules unless you are deliberately tightening beyond the source: the group's egress would then be exactly the egress rules converted from this firewall, and where it declared none that denies ALL outbound traffic. 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. A source_ranges or destination_ranges entry that is an IPv6 CIDR is REFUSED - no rule is generated for it, and the refusal is reported as a blocker naming the exact range, because a rule emitted with an IPv6 remote is rejected when it is applied. Do NOT translate an IPv6 range to an IPv4 one, it selects different hosts. The firewall's IPv4 ranges still convert; if every range is IPv6 the whole firewall blocks, because the group it would produce allows nothing.

AttributeOutcomeNotes
nameConvertedbecomes the generated frostmoln_security_group name.
networkConverteda direct google_compute_network reference becomes vpc_id on the generated security group.
directionConvertedINGRESS/EGRESS becomes the direction of each generated rule.
source_rangesConvertedthe ingress source CIDRs become remote_cidr on the generated rules (fanned out).
destination_rangesConvertedthe egress destination CIDRs become remote_cidr on the generated rules (fanned out).
allowConvertedeach allow protocol/port becomes one or more frostmoln_security_group_rule resources.
denyManual action required
target_tagsManual action required
target_service_accountsManual action required
source_tagsManual action required
source_service_accountsManual action required
priorityNot carried over
disabledManual action required
log_configNot carried over
descriptionNot carried over
projectNot needed on Frostmoln

google_compute_forwarding_rule → frostmoln_load_balancer — partially supported

Forwarding rules map to the frontend of a frostmoln_load_balancer (an L4 network load balancer, provider_type ovn); the port and backend become a frostmoln_lb_listener and frostmoln_lb_pool you must create from the target_pool.

This is a PARTIAL L4 decomposition. A GCP forwarding rule is only the load-balancer frontend — the port(s) become a frostmoln_lb_listener and the target_pool becomes a frostmoln_lb_pool with frostmoln_lb_member resources, which you must wire up (set load_balancer_id on them to this load balancer). load_balancing_scheme EXTERNAL becomes scheme public (which requires a public_ip_id), INTERNAL becomes internal. A public load balancer needs a frostmoln_public_ip. L7 (HTTP(S)) forwarding rules that target a backend_service / URL map are not supported.

AttributeOutcomeNotes
nameMapped to name
load_balancing_schemeConverted to schemeA public scheme requires a public_ip_id — create a frostmoln_public_ip for the load balancer.
networkConverted to vpc_idA direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually.
subnetworkConverted to subnet_idA direct google_compute_subnetwork reference is rewritten to the converted frostmoln_subnet id; otherwise set subnet_id manually.
ip_protocolNot carried over
port_rangeNot carried over
portsNot carried over
all_portsManual action required
targetManual action required
backend_serviceManual action required
ip_addressManual action required
labelsConverted to tagsGCP labels become frostmoln tags.
regionConvertedFrostmoln is single-region today; the platform default region applies.
allow_global_accessNot carried over
network_tierNot carried over
service_labelNot carried over
descriptionNot carried over
projectNot needed on Frostmoln
  • The converter adds provider_type automatically. a network forwarding rule is an L4 load balancer (provider_type ovn); change it to amphora for an L7 load balancer.
  • The converter adds vpc_id automatically. frostmoln_load_balancer requires a VPC; set vpc_id to the converted frostmoln_vpc id.
  • The converter adds subnet_id automatically. frostmoln_load_balancer requires a subnet; set subnet_id to the converted frostmoln_subnet id.

google_compute_health_check → frostmoln_lb_health_monitor — partially supported

Health checks map to frostmoln_lb_health_monitor; the protocol block (tcp/http/https) becomes type, and the interval/timeout/thresholds carry over.

The required load_balancer_id and pool_id are FM-TODO placeholders — set them to the converted load balancer and the pool this monitor checks. tcp_health_check becomes type tcp, http_health_check becomes type http (with url_path from request_path), https_health_check becomes type https. SSL, HTTP/2, and gRPC health checks have no equivalent. Health checks run against each member's port, so the per-check port is dropped.

AttributeOutcomeNotes
check_interval_secMapped to delay
timeout_secMapped to timeout
healthy_thresholdMapped to max_retries
unhealthy_thresholdNot carried over
tcp_health_checkConverted to typebecomes type = "tcp"; the port is set per member.
http_health_checkConverted to typebecomes type = "http" with url_path from request_path; the port is set per member.
https_health_checkConverted to typebecomes type = "https" with url_path from request_path; the port is set per member.
ssl_health_checkManual action required
http2_health_checkManual action required
grpc_health_checkManual action required
nameNot carried over
descriptionNot carried over
log_configNot carried over
projectNot needed on Frostmoln
  • The converter adds type automatically. frostmoln_lb_health_monitor requires a type; set it to tcp, http, or https (the protocol block sets it when present).
  • The converter adds load_balancer_id automatically. frostmoln_lb_health_monitor requires load_balancer_id; set it to the converted load balancer.
  • The converter adds pool_id automatically. frostmoln_lb_health_monitor requires pool_id; set it to the converted frostmoln_lb_pool.

google_compute_instance → frostmoln_instance — partially supported

Compute Engine instances map to frostmoln_instance: the machine type is capability-matched to a flavor, the boot disk image becomes a frostmoln_image lookup, the network interface becomes subnet_id/vpc_id (an access_config becomes a frostmoln_public_ip), and metadata SSH keys become frostmoln_ssh_key resources.

machine_type is parsed algorithmically (predefined families by their class ratio, custom-N-M directly, shared-core types by their listed size) and capability-matched against the platform flavor catalog — offline a reviewed placeholder is emitted. boot_disk.initialize_params.image becomes a frostmoln_image lookup whose name needs review. GCP NETWORK tags (the tags argument) are firewall selectors, NOT frostmoln tags — they are DROPPED (mapping them to tags would be silently wrong); the firewall→security_group conversion notes which instances need the group. labels become frostmoln tags. A service_account block is BLOCKED (there is no IAM; grant access with scoped API credentials). Preemptible/spot scheduling and shielded-VM settings are dropped.

AttributeOutcomeNotes
nameMapped to name
machine_typeConverted to flavor_idParsed algorithmically into vCPUs/RAM and capability-matched against the platform flavor catalog, emitted as a frostmoln_flavor data source lookup.
zoneConvertedThe platform picks the zone; set zone to a zone id to pin one.
boot_diskConverted to image_idinitialize_params.image becomes image_id (a frostmoln_image lookup); the disk size and type are dropped (the flavor and platform tier determine them).
network_interfaceConvertedsubnetwork becomes subnet_id, network becomes vpc_id, and an access_config (external IP) becomes a generated frostmoln_public_ip bound to the instance.
metadataConverted to ssh_key_namesSSH keys in metadata.ssh-keys become generated frostmoln_ssh_key resources; a startup-script/user-data key is flagged (move it to user_data).
metadata_startup_scriptMapped to user_dataThe startup script becomes plain-text user_data.
labelsConverted to tagsGCP labels become frostmoln tags.
tagsNot carried over
service_accountManual action required
schedulingNot carried over
shielded_instance_configNot carried over
confidential_instance_configNot carried over
can_ip_forwardNot carried over
deletion_protectionNot carried over
allow_stopping_for_updateNot needed on Frostmoln
attached_diskManual action required
guest_acceleratorManual action required
min_cpu_platformNot carried over
resource_policiesManual action required
advanced_machine_featuresNot carried over
reservation_affinityNot carried over
enable_displayNot carried over
hostnameNot carried over
descriptionNot carried over
desired_statusNot carried over
projectNot needed on Frostmoln
  • The converter adds flavor_id automatically. frostmoln_instance requires a flavor; set flavor_id to a platform flavor (see fm compute flavor list).
  • The converter adds image_id automatically. frostmoln_instance requires an image; set image_id to a platform image (see fm compute image list).

data.google_compute_network → frostmoln_vpc — partially supported

The google_compute_network data source maps to the frostmoln_vpc data source, which selects a VPC by id or name.

frostmoln_vpc looks up a VPC by id or name. A GCP network has no CIDR, so references to the exported subnetworks / gateway attributes have no equivalent; use the VPC id.

AttributeOutcomeNotes
nameMapped to name
projectManual action required

google_compute_network → frostmoln_vpc — partially supported

VPC networks map to frostmoln_vpc; because a GCP network carries no CIDR (subnets define their own ranges), a required cidr is synthesized as an FM-TODO placeholder to set to your VPC supernet.

GCP networks are global and have NO address range of their own — each subnetwork defines its ip_cidr_range. frostmoln_vpc requires a single cidr (a supernet the subnets fall within), so an FM-TODO placeholder is emitted: set it to the supernet that contains your subnets. Auto-mode networks (auto_create_subnetworks) create per-region subnets automatically — those subnets have no Terraform resource and are not converted; recreate them as frostmoln_subnet. routing_mode and mtu are platform-managed. The converted VPC has NO outbound internet access on its own: outbound is an explicit frostmoln_gateway (one per VPC, egressing from an address the platform draws for it; name a Public IP of your own with public_ip_id where a partner allow-lists your source address, and that address is billed as a Public IP), and without it the VPC also has no DNS resolution and no managed-service connectivity, because those are reached over routes that exist only while the egress path does. A google_compute_router_nat in the source configuration does not convert into one — see its entry.

AttributeOutcomeNotes
nameMapped to name
descriptionMapped to description
auto_create_subnetworksNot carried over
routing_modeNot carried over
mtuNot carried over
delete_default_routes_on_createNot carried over
network_firewall_policy_enforcement_orderNot carried over
projectNot needed on Frostmoln
  • The converter adds cidr automatically. frostmoln_vpc requires a cidr but a GCP network has none — set this to the supernet that contains your subnets (the placeholder must be replaced).

google_compute_snapshot → frostmoln_snapshot — partially supported

Disk snapshots map to frostmoln_snapshot; the source disk becomes volume_id.

source_disk references the disk the snapshot was taken from — a direct google_compute_disk reference is rewritten to the converted frostmoln_volume id. Snapshot encryption keys are customer-managed on GCP and have no equivalent (snapshots are encrypted with platform-managed keys).

AttributeOutcomeNotes
nameMapped to name
descriptionMapped to description
source_diskConverted to volume_idA direct google_compute_disk reference is rewritten to the converted frostmoln_volume id; otherwise set volume_id manually.
labelsConverted to tagsGCP labels become frostmoln tags.
zoneNot needed on Frostmoln
storage_locationsNot carried over
snapshot_encryption_keyManual action required
source_disk_encryption_keyManual action required
chain_nameNot carried over
projectNot needed on Frostmoln
  • The converter adds volume_id automatically. frostmoln_snapshot requires a source volume; set volume_id to the converted frostmoln_volume id.

data.google_compute_subnetwork → frostmoln_subnet — partially supported

The google_compute_subnetwork data source maps to the frostmoln_subnet data source, which selects a subnet by id or name.

frostmoln_subnet looks up a subnet by id or name. The region is platform-managed, and secondary IP ranges have no equivalent; use ip_cidr_range (cidr).

AttributeOutcomeNotes
nameMapped to name
regionManual action required
projectManual action required

google_compute_subnetwork → frostmoln_subnet — partially supported

Subnetworks map to frostmoln_subnet; ip_cidr_range becomes cidr, the parent network becomes vpc_id, and the region becomes the platform zone.

network references the parent network — a direct google_compute_network reference is rewritten to the converted frostmoln_vpc id. Secondary IP ranges (alias-IP ranges) are dropped — recreate them manually if needed. Private Google Access, flow logs, and purpose/role (for proxy-only or PSC subnets) are dropped (platform-managed).

AttributeOutcomeNotes
nameMapped to name
descriptionMapped to description
ip_cidr_rangeMapped to cidr
networkConverted to vpc_idA direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually.
regionConvertedThe platform picks the zone; set zone to a zone id to pin one.
secondary_ip_rangeNot carried over
private_ip_google_accessNot carried over
private_ipv6_google_accessNot carried over
purposeNot carried over
roleNot carried over
log_configNot carried over
stack_typeNot carried over
ipv6_access_typeManual action required
projectNot needed on Frostmoln
  • The converter adds vpc_id automatically. frostmoln_subnet requires a VPC; set vpc_id to the converted frostmoln_vpc id.

google_compute_target_pool → frostmoln_lb_pool — partially supported

Target pools map to frostmoln_lb_pool; the required load_balancer_id is an FM-TODO placeholder (set it to the converted forwarding rule's load balancer), and pool instances become frostmoln_lb_member resources you must create.

A required lb_algorithm defaults to round_robin — note that a network load balancer (provider_type ovn) supports only source_ip_port, so change lb_algorithm when attaching this pool to an ovn load balancer. Pool instances become frostmoln_lb_member resources: recreate one per backend, using the instance's private IP as address (members are addresses, not instance references). The health_check reference becomes a frostmoln_lb_health_monitor.

AttributeOutcomeNotes
nameMapped to name
instancesManual action required
health_checksManual action required
session_affinityNot carried over
backup_poolManual action required
failover_ratioNot carried over
regionConvertedFrostmoln is single-region today; the platform default region applies.
descriptionNot carried over
projectNot needed on Frostmoln
  • The converter adds protocol automatically. frostmoln_lb_pool requires a protocol; a target pool is TCP-based — verify tcp or set it (tcp/udp/http/https).
  • The converter adds lb_algorithm automatically. frostmoln_lb_pool requires lb_algorithm; a network load balancer (ovn) supports only source_ip_port — change it when attaching to an ovn load balancer.
  • The converter adds load_balancer_id automatically. frostmoln_lb_pool requires load_balancer_id; set it to the converted load balancer (from the forwarding rule).

google_container_cluster → frostmoln_kubernetes_cluster — partially supported

GKE clusters map to frostmoln_kubernetes_cluster; the default node_config becomes the required initial_node_pool (machine_type reported as a size, with flavor_id left for you to set from fm kubernetes flavor list), and the API endpoint's exposure does not carry over (it is not a per-cluster setting on the platform).

The API endpoint's exposure does NOT carry over — it is not a per-cluster setting on the platform (see private_cluster_config), and nothing is made public by the conversion. Public WORKLOAD traffic has no cluster-level equivalent either: a managed cluster is NOT given an ingress load balancer, so there is no attribute for a GKE public entrypoint to convert into and none is emitted. Expose a workload the standard Kubernetes way instead — a Service of type=LoadBalancer inside the cluster, which the platform provisions a load balancer for. That is an in-cluster step (kubectl/Helm), not Terraform, so this conversion cannot do it for you. And it is only half a replacement today: such a Service can be given an INTERNAL address only, because a per-Service PUBLIC address is not built yet, so a publicly reachable workload entrypoint is an open GAP. Do not assume the converted configuration exposes anything — carry the source's public entrypoint forward on your migration checklist and plan it by hand. network/subnetwork become vpc_id/subnet_id. When the default node pool is removed (remove_default_node_pool) and real pools are defined as google_container_node_pool, the initial_node_pool is an FM-TODO placeholder (the separate node pools convert to frostmoln_kubernetes_node_pool). Autopilot, network policy, master authorized networks, and add-on configs have no equivalent and are dropped or blocked. Workload Identity IS supported on managed Kubernetes — it is switched on for the tenant rather than per cluster, so workload_identity_config carries nothing over. The tenant must hold the workload-identity entitlement BEFORE the cluster is created; it cannot be enabled on an existing one. Each google_service_account_iam_member that federated a Kubernetes service account has to be rewritten by hand as a frostmoln_workload_identity_binding (the converter has no mapping for that type yet); grant the binding with a frostmoln_iam_policy attached by frostmoln_iam_policy_attachment (its flat scopes list is optional and coarser). Note also that GKE's per-pool node_config.workload_metadata_config is not carried over.

AttributeOutcomeNotes
nameMapped to name
min_master_versionMapped to versionVerify the version is offered on the platform (fm kubernetes version list).
networkConverted to vpc_idA direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually.
subnetworkConverted to subnet_idA direct google_compute_subnetwork reference is rewritten to the converted frostmoln_subnet id; otherwise set subnet_id manually.
node_configConverted to initial_node_poolThe default node_config (with initial_node_count) becomes the required initial_node_pool object. machine_type is parsed for its vCPUs and RAM and reported; flavor_id is left as an FM-TODO to set from fm kubernetes flavor list.
private_cluster_configNot carried overThe Kubernetes API endpoint's exposure is not configurable on the platform, so there is nothing to set here. enable_private_endpoint = true carries over faithfully — the managed control plane's API endpoint is private and reached from inside your VPC. A cluster with a PUBLIC endpoint does not: plan for kubectl from inside the VPC, or through the platform's authenticated access path. If what you exposed publicly was your WORKLOAD traffic, that has no setting on the converted cluster either: a managed cluster is not given an ingress load balancer, and a workload is exposed with a Kubernetes Service of type=LoadBalancer inside the cluster. Only INTERNAL addresses are available for such a Service today, so a PUBLIC workload entrypoint is an open GAP — plan it as manual work rather than expecting the converted configuration to provide one.
initial_node_countNot needed on Frostmoln
remove_default_node_poolNot needed on Frostmoln
master_authorized_networks_configNot carried over
workload_identity_configNot carried overWorkload identity is available on managed Kubernetes, but it is switched on for your tenant rather than per cluster, so there is nothing to configure here. Your tenant must hold the workload-identity entitlement BEFORE the cluster is created — it cannot be turned on for a cluster that already exists. Bind each Kubernetes service account with frostmoln_workload_identity_binding, granted by a frostmoln_iam_policy attached with frostmoln_iam_policy_attachment (its flat scopes list is optional and coarser).
release_channelNot carried over
addons_configNot carried over
network_policyNot carried over
ip_allocation_policyNot carried over
enable_autopilotManual action required
cluster_autoscalingManual action required
logging_serviceNot carried over
monitoring_serviceNot carried over
logging_configNot carried over
monitoring_configNot carried over
maintenance_policyNot carried over
locationNot needed on Frostmoln
node_locationsNot carried over
resource_labelsNot carried over
deletion_protectionNot carried over
datapath_providerNot carried over
projectNot needed on Frostmoln
  • The converter adds initial_node_pool automatically. frostmoln_kubernetes_cluster requires an initial node pool; set flavor_id to a platform flavor (see fm kubernetes flavor list) — the real pools convert to frostmoln_kubernetes_node_pool.
  • The converter adds version automatically. frostmoln_kubernetes_cluster requires a version; set it to an offered version (fm kubernetes version list).
  • The converter adds vpc_id automatically. frostmoln_kubernetes_cluster requires a VPC; set vpc_id to the converted frostmoln_vpc id.
  • The converter adds subnet_id automatically. frostmoln_kubernetes_cluster requires a subnet; set subnet_id to the converted frostmoln_subnet id.

google_container_node_pool → frostmoln_kubernetes_node_pool — partially supported

GKE node pools map to frostmoln_kubernetes_node_pool; node_config.machine_type's size is reported and flavor_id is left for you to set, and node_count carries over.

A node pool draws flavor_id from the Kubernetes node-flavor catalog, which is separate from the compute one — so the converter reports the source machine_type's vCPUs and RAM and leaves flavor_id as an FM-TODO for you to set from fm kubernetes flavor list. cluster references the parent cluster — a direct google_container_cluster reference is rewritten to the converted cluster id. Autoscaling has no equivalent (set a fixed node_count). The pool name must be a lowercase DNS label of at most 18 characters. Node labels, taints, and per-pool locations are dropped or blocked.

AttributeOutcomeNotes
nameMapped to nameThe pool name must be a lowercase DNS label of at most 18 characters.
clusterConverted to cluster_idA direct google_container_cluster reference is rewritten to the converted frostmoln_kubernetes_cluster id.
node_configConverted to flavor_idnode_config.machine_type is parsed for its vCPUs and RAM and reported; flavor_id is left as an FM-TODO to set from fm kubernetes flavor list.
node_countMapped to node_count
autoscalingManual action required
initial_node_countNot needed on Frostmoln
managementNot carried over
upgrade_settingsNot carried over
max_pods_per_nodeNot carried over
node_locationsNot carried over
locationNot needed on Frostmoln
versionNot carried over
network_configNot carried over
projectNot needed on Frostmoln
  • The converter adds flavor_id automatically. frostmoln_kubernetes_node_pool requires a flavor; set flavor_id to a platform flavor (see fm kubernetes flavor list).

google_dns_managed_zone → frostmoln_dns_zone — partially supported

Public DNS zones map to frostmoln_dns_zone; dns_name becomes the zone name (normalized to a lowercase FQDN) and a required SOA email is synthesized as a placeholder.

Only PUBLIC zones convert — a PRIVATE zone has no equivalent and BLOCKS the conversion (converting it to a public zone would expose it). The GCP resource name (the name argument) is dropped: the zone name IS the domain on Frostmoln. The required SOA admin email cannot come from GCP — an FM-TODO placeholder is emitted. DNSSEC and split-horizon (peering/forwarding) configs are dropped or blocked.

AttributeOutcomeNotes
dns_nameConverted to nameNormalized to a lowercase fully qualified domain with a trailing dot, e.g. "example.com."
nameNot carried over
descriptionMapped to description
visibilityConvertedpublic zones convert; a private zone blocks the conversion.
labelsConverted to tagsGCP labels become frostmoln tags.
dnssec_configNot carried over
private_visibility_configManual action required
forwarding_configManual action required
peering_configManual action required
cloud_logging_configNot carried over
force_destroyNot needed on Frostmoln
projectNot needed on Frostmoln
  • The converter adds email automatically. the SOA admin email is required; replace the placeholder with a real contact address.

google_dns_record_set → frostmoln_dns_record — partially supported

DNS record sets map to frostmoln_dns_record; rrdatas becomes records and the record name becomes zone-relative.

Record names are zone-relative on Frostmoln (the zone name is appended automatically). When the managed_zone references an in-config google_dns_managed_zone with a static dns_name, the fully qualified record name has that suffix stripped automatically; otherwise a fully qualified name blocks — strip the zone suffix, or use "@" for the apex. Supported types: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, PTR. Weighted/geo/failover routing_policy has no equivalent.

AttributeOutcomeNotes
nameConvertedRecord names are zone-relative; a name referencing an in-config zone's dns_name is stripped automatically.
managed_zoneConverted to zone_idA direct google_dns_managed_zone reference is rewritten to the converted frostmoln_dns_zone id.
typeConvertedSupported types carry over; SOA and other types have no equivalent (SOA is platform-managed).
rrdatasMapped to recordsThe record data list becomes the records set.
ttlMapped to ttl
routing_policyManual action required
projectNot needed on Frostmoln

google_redis_instance → frostmoln_redis_instance — partially supported

Memorystore Redis instances map to frostmoln_redis_instance; the version carries over and the memory size does not map to a platform flavor, so flavor_id is a placeholder.

The managed cache serves the cache protocol in PLAINTEXT on port 6379 at its private address in your VPC and has no TLS listener, whatever the source configuration asked for — the AUTH password therefore also crosses the wire in cleartext, as do the keys and values themselves; and with no TLS there is no integrity protection either, so anything on the network path inside your VPC can read and modify the traffic. A transit_encryption_mode of SERVER_AUTHENTICATION BLOCKS the conversion for that reason; DISABLED converts. GCP sizes Redis by memory_size_gb rather than vCPU/RAM, so flavor_id, vpc_id, and subnet_id are FM-TODO placeholders — set flavor_id to the platform flavor whose memory tier matches. The tier (BASIC / STANDARD_HA) has no direct equivalent: STANDARD_HA is high-availability, which frostmoln_redis_instance does not expose. redis_configs are dropped — set eviction_policy and persistence_mode on the instance manually.

AttributeOutcomeNotes
nameMapped to name
redis_versionConverted to versionREDIS_7_0 becomes "7"; verify the version is offered (fm cache redis version list).
authorized_networkConverted to vpc_idA direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually.
memory_size_gbNot carried over
tierNot carried over
redis_configsNot carried over
reserved_ip_rangeManual action required
connect_modeNot carried over
transit_encryption_modeConvertedDISABLED converts and the flag is dropped; SERVER_AUTHENTICATION blocks the whole resource — the managed cache has no TLS listener, so converting the instance without the attribute would silently turn a TLS-encrypted cache into a plaintext one.
auth_enabledNot needed on Frostmoln
replica_countNot carried over
read_replicas_modeNot carried over
labelsNot carried over
regionNot needed on Frostmoln
location_idNot carried over
alternative_location_idNot carried over
maintenance_policyNot carried over
projectNot needed on Frostmoln
  • The converter adds version automatically. frostmoln_redis_instance requires a version; set it to an offered version (fm cache redis version list).
  • The converter adds flavor_id automatically. frostmoln_redis_instance requires a flavor; the GCP memory size does not map — set flavor_id (see fm cache flavor list).
  • The converter adds vpc_id automatically. frostmoln_redis_instance requires a VPC; set vpc_id to the converted frostmoln_vpc id.
  • The converter adds subnet_id automatically. frostmoln_redis_instance requires a subnet; set subnet_id to the converted frostmoln_subnet id.

google_secret_manager_secret → frostmoln_secret — partially supported

Secret Manager secrets map to frostmoln_secret; the secret_id becomes the name and the secret value is set on the frostmoln_secret directly.

On GCP the secret value lives in a separate google_secret_manager_secret_version — Frostmoln stores the value on the secret itself, so a required secret_value is an FM-TODO placeholder: set it from the corresponding secret version's secret_data. Replication is not applicable (data is stored in the single EU region). GCP labels become frostmoln tags.

AttributeOutcomeNotes
secret_idMapped to name
labelsConverted to tagsGCP labels become frostmoln tags.
replicationNot needed on Frostmoln
rotationNot carried over
topicsNot carried over
ttlNot carried over
expire_timeNot carried over
version_aliasesNot carried over
annotationsNot carried over
projectNot needed on Frostmoln
  • The converter adds secret_value automatically. frostmoln_secret requires the value inline; set secret_value from the corresponding google_secret_manager_secret_version's secret_data.

google_sql_database_instance → frostmoln_postgres_instance — partially supported

Cloud SQL PostgreSQL instances map to frostmoln_postgres_instance; the settings block becomes storage_gb/ha_enabled with flavor_id left for you to set, and database_version becomes the engine version.

This converter maps google_sql_database_instance to frostmoln_postgres_instance — a MYSQL_* database_version BLOCKS the conversion (recreate MySQL instances as frostmoln_mysql_instance). A read replica (master_instance_name) also blocks (recreate as frostmoln_postgres_read_replica). settings.disk_size becomes storage_gb, and settings.availability_type = REGIONAL becomes ha_enabled. A managed database draws flavor_id from the managed-database flavor catalog, which is separate from the compute one — so the converter reports settings.tier's vCPUs and RAM and leaves flavor_id as an FM-TODO for you to set from fm database flavor list. frostmoln_postgres_instance requires a VPC and subnet — vpc_id and subnet_id are FM-TODO placeholders (set them to the converted network). Administrator credentials are platform-issued and dropped.

AttributeOutcomeNotes
nameMapped to name
database_versionConverted to versionPOSTGRES_16 becomes "16"; a MYSQL_* version blocks (use frostmoln_mysql_instance).
settingsConverteddisk_size becomes storage_gb and availability_type REGIONAL becomes ha_enabled; tier is parsed for its vCPUs and RAM and reported, with flavor_id left as an FM-TODO to set from fm database flavor list.
master_instance_nameManual action required
replica_configurationManual action required
root_passwordNot carried over
regionNot needed on Frostmoln
deletion_protectionNot carried over
encryption_key_nameManual action required
instance_typeNot carried over
maintenance_versionNot carried over
projectNot needed on Frostmoln
  • The converter adds version automatically. frostmoln_postgres_instance requires a version; set it to an offered version (fm database postgres version list).
  • The converter adds vpc_id automatically. frostmoln_postgres_instance requires a VPC; Cloud SQL instances have no VPC concept — set vpc_id to the converted frostmoln_vpc id.
  • The converter adds subnet_id automatically. frostmoln_postgres_instance requires a subnet; set subnet_id to the converted frostmoln_subnet id.

google_storage_bucket → frostmoln_bucket — partially supported

Storage buckets map to frostmoln_bucket (name, versioning, tags); the location becomes the platform region, and IAM, lifecycle, CORS, and website hosting have no equivalent.

The bucket versioning block (enabled = true/false) becomes the versioning string (enabled/suspended). GCP labels become frostmoln tags. Buckets are private — re-grant access with S3 credentials (frostmoln_s3_credential) scoped to the bucket. uniform_bucket_level_access and public_access_prevention are the platform default (private) and are dropped. Lifecycle rules, CORS, website hosting, and retention policies have no equivalent yet.

AttributeOutcomeNotes
nameMapped to name
locationConvertedFrostmoln is single-region today; the platform default region applies.
versioningConvertedversioning.enabled = true becomes versioning = "enabled"; false becomes "suspended".
storage_classNot carried over
labelsConverted to tagsGCP labels become frostmoln tags.
uniform_bucket_level_accessNot needed on Frostmoln
public_access_preventionNot carried over
lifecycle_ruleManual action required
corsManual action required
websiteManual action required
encryptionNot needed on Frostmoln
loggingNot carried over
retention_policyManual action required
autoclassNot carried over
requester_paysNot needed on Frostmoln
force_destroyNot needed on Frostmoln
default_event_based_holdManual action required
projectNot needed on Frostmoln

google_storage_hmac_key → frostmoln_s3_credential — partially supported

HMAC keys map to frostmoln_s3_credential (S3-compatible access keys); the service-account scoping is dropped.

A GCP HMAC key is scoped to a service account — Frostmoln S3 credentials are scoped to buckets/actions instead, so the service_account_email is dropped. A required credential name is synthesized from the resource address. Scope the credential with allowed_buckets / allowed_actions after the conversion.

AttributeOutcomeNotes
service_account_emailNot carried over
stateNot carried over
projectNot needed on Frostmoln
  • The converter adds name automatically. frostmoln_s3_credential requires a name; it is taken from the resource address.

Resources without an equivalent

ResourceWhat happens
google_bigquery_datasetBigQuery has no equivalent; run analytics on a managed PostgreSQL/MySQL instance or self-hosted engine.
google_cloud_run_serviceManaged container serverless (Cloud Run) has no equivalent; deploy containers on frostmoln_kubernetes_cluster.
google_cloudfunctions_functionServerless functions have no equivalent; run code on a frostmoln_instance or in frostmoln_kubernetes_cluster.
google_compute_backend_serviceL7 (HTTP(S)) load-balancer backend services have no equivalent yet; recreate the load balancer from its L4 forwarding rule and target pool.
google_compute_network_peeringVPC network peering has no equivalent; connect workloads within a single VPC.
google_compute_routeRouting inside a VPC is platform-managed and custom routes are removed; a default route to the internet is not one of them — outbound comes from the VPC's gateway, a separate resource you must add.
google_compute_routerRouting inside a VPC is platform-managed and Cloud Routers are removed; if this router hosted a Cloud NAT, that outbound path is NOT removed with it — see google_compute_router_nat for the gateway to add.
google_compute_router_natA 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 Cloud NATs serving one network collapse into a single gateway.
google_compute_router_nat_addressA frostmoln_gateway carries a single source address — the platform's, or one Public IP you own and name on the gateway — not a list of addresses you reserved and assigned.
google_compute_url_mapURL maps (L7 path-based routing) have no equivalent; terminate HTTP routing in your own reverse proxy.
google_compute_vpn_gatewayCloud VPN gateways have no equivalent; terminate site-to-site VPNs on a customer-managed instance.
google_kms_crypto_keyCustomer-managed encryption keys have no equivalent; resources are encrypted with platform-managed keys.
google_project_iam_memberThere are no project-level IAM bindings; attach a frostmoln_iam_policy to the principal instead.
google_pubsub_subscriptionPub/Sub has no equivalent; Frostmoln's managed message broker speaks AMQP (LavinMQ), not Pub/Sub.
google_pubsub_topicPub/Sub has no equivalent; Frostmoln's managed message broker speaks AMQP (LavinMQ), not Pub/Sub.
google_secret_manager_secret_versionSecret versions have no standalone equivalent; the value is set on the frostmoln_secret directly.
google_service_accountThere is no standalone service-account resource; a Kubernetes workload gets its identity from frostmoln_workload_identity_binding, and anything else uses a frostmoln_api_key.
google_sql_databaseDatabases are created inside the managed instance; a standalone database resource has no equivalent.
google_sql_userDatabase users are managed inside the instance; a standalone user resource has no equivalent.
google_storage_bucket_objectIndividual bucket objects are not managed as Terraform resources; upload objects with the S3 API or fm CLI.

google_bigquery_dataset

Frostmoln has no serverless data warehouse — recreate analytical workloads on frostmoln_postgres_instance or a self-hosted engine on compute.

google_cloud_run_service

Frostmoln offers managed Kubernetes rather than Cloud Run — deploy the container image to a frostmoln_kubernetes_cluster (or run it on a VM).

google_cloudfunctions_function

Frostmoln offers no function-as-a-service — repackage Cloud Functions as a container on Kubernetes or a service on a VM.

google_compute_backend_service

Frostmoln load balancers do not yet support URL-map/path-based routing. Convert the L4 network load balancer (google_compute_forwarding_rule + google_compute_target_pool) instead, or terminate HTTP routing in your own reverse proxy.

google_compute_network_peering

Frostmoln does not support inter-VPC peering — place workloads that must communicate in the same frostmoln_vpc, or route between them at the application layer.

google_compute_route

Subnet-to-subnet routing within a Frostmoln VPC is automatic, so a static route describing it has nothing to convert to.

A route with next_hop_gateway = "default-internet-gateway" is a different matter: nothing the platform does replaces it. 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 managed-service connectivity either. See the google_compute_router_nat entry for what to add, and how to give it a source address you can publish.

google_compute_router

Frostmoln has no Cloud Router: subnet-to-subnet routing within a VPC is automatic, and there are no BGP sessions to advertise into.

Read the summary before deleting anything, though: a Cloud Router is also where a Cloud NAT hangs. Removing the router does not remove the need for outbound connectivity, and nothing replaces it implicitly. 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 managed-service connectivity either. See google_compute_router_nat in this report for what to add, and how to give it a source address you can publish.

google_compute_router_nat

This is not a resource the platform makes unnecessary — it is one you have to replace. A Frostmoln VPC's outbound path is an explicit resource, and a VPC without one is an isolated network: no outbound internet, and — because the platform DNS resolver and the managed-service control plane are reached over routes that exist only while that path does — no name resolution and no managed-service connectivity either. Attach one to the converted VPC (the frostmoln_vpc this NAT's router referenced through its network):

resource "frostmoln_gateway" "main" {
  vpc_id = frostmoln_vpc.main.id
  mode   = "public_ip"
}

That gateway IS the translation Cloud NAT performed: every instance in the VPC egresses through it. Its source address is drawn by the platform, and you do not choose which one you get, so it is not an address to publish. That matters if this Cloud NAT used nat_ip_allocate_option = "MANUAL_ONLY" with reserved nat_ips: to keep a source address you can hand out, allocate it yourself and name it:

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 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.

Two shapes do not carry over. A VPC has AT MOST ONE gateway, while this configuration may hold one Cloud NAT per region for what becomes a single VPC; a single frostmoln_gateway replaces all of them, and that many-to-one collapse is left to you to make rather than performed quietly. And source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS" has no equivalent: the gateway serves the whole VPC, so a per-subnet NAT selection must be reshaped as separate VPCs or handled with security groups.

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>

google_compute_router_nat_address

This resource manages the reserved external addresses a Cloud NAT translates to. Frostmoln has no equivalent assignment: the VPC's gateway carries exactly ONE source address, named on the gateway itself. Left unnamed, the gateway egresses from an address the platform draws — one you do not choose and should not publish. Naming a Public IP you own is the analogue, 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.

A list of addresses — the reason this resource exists, usually port headroom or a published allow-list range — has no counterpart: one gateway, one address. If a partner allow-lists several addresses today, that expectation has to be renegotiated before this configuration will work.

The gateway itself is not created for you; see google_compute_router_nat, 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>

google_compute_url_map

Frostmoln load balancers route at L4 (and L7 without path rules); URL-map path/host routing has no equivalent — run a reverse proxy (nginx/Traefik) behind the load balancer for path routing.

google_compute_vpn_gateway

Frostmoln does not offer a managed VPN gateway — run a VPN endpoint (WireGuard/IPsec) on a frostmoln_instance if site-to-site connectivity is required.

google_kms_crypto_key

Frostmoln encrypts volumes, snapshots, and objects with platform-managed keys — there is no Cloud KMS equivalent. Store application secrets in frostmoln_secret.

google_project_iam_member

Frostmoln grants access from the principal side: a frostmoln_iam_policy (document composed with the frostmoln_iam_policy_document data source) attached with frostmoln_iam_policy_attachment to an api_key, workload_identity, or group. The roles themselves do not carry over - a GCP role has no mechanical translation to Frostmoln operations and FRNs - so review every dropped binding and re-express what it allowed.

google_pubsub_subscription

Pub/Sub subscriptions have no protocol overlap with the managed AMQP broker — recreate consumers/queues on the broker manually.

google_pubsub_topic

Pub/Sub is a proprietary push/pull messaging service with no protocol overlap with the managed AMQP broker — recreate the messaging topology on the broker manually.

google_secret_manager_secret_version

Frostmoln stores the secret value on the frostmoln_secret (secret_value) and manages versioning internally — take the secret_data from this version and set it as secret_value on the converted secret.

google_service_account

GKE Workload Identity - a service account impersonated by a Kubernetes service account - has a counterpart: frostmoln_workload_identity_binding binds a namespace and service account in a Frostmoln-managed Kubernetes cluster, with no long-lived credential, and a frostmoln_iam_policy attached to that workload_identity carries the permissions - the preferred grant, and the counterpart of the IAM bindings you attached to the service account. The binding's own flat scopes list is OPTIONAL and coarser (a scope grants across a whole service). A binding created before its grant exists is INERT rather than open, and removing its LAST grant is rejected - delete the binding to remove a workload's access. As on GKE, the Kubernetes ServiceAccount must be annotated (frostmoln.cloud/workload-identity=true) before a pod running as it gets a credential. There is no account OBJECT to create first, so this resource disappears rather than converting. A service account used OUTSIDE a Frostmoln-managed cluster, or one whose key was exported, becomes a frostmoln_api_key (or frostmoln_s3_credential for bucket access) held as a secret.

google_sql_database

Create databases inside the frostmoln_postgres_instance / frostmoln_mysql_instance after it is provisioned; there is no per-database Terraform resource.

google_sql_user

Create database users inside the frostmoln_postgres_instance / frostmoln_mysql_instance after it is provisioned; the admin account is platform-issued.

google_storage_bucket_object

Frostmoln manages buckets, not their contents — upload objects to the frostmoln_bucket using S3-compatible tooling after the conversion.


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.