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.
Provider configuration and tags
Provider block
Each provider "google" or provider "google-beta" block becomes a provider "frostmoln" block, and an aliased block keeps a literal alias. Project, region, zone, credentials, service endpoints and the attribution-label settings 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 labels
The provider's default_labels 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; and a provider block removed because another block becomes the same frostmoln configuration does not bring its default_labels (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. Google label keys and values (lowercase letters, digits, _ and -) mostly carry unchanged: a key ending in _ or -, or a key or value with international characters, is outside the accepted shape, and a label such as instance_group starts with a prefix the frostmoln provider refuses as a default. When a google and a google-beta block become the same frostmoln configuration and their default_labels are identical, those defaults apply to the resources of both.
References to the merged tag set
A reference to a resource's terraform_labels or effective_labels 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_labels 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. Resource-manager tags (google_tags_tag_key, google_tags_tag_value, google_tags_tag_binding) are an organisation-level construct with no converter mapping.
Tag colours
Google labels and resource-manager 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.
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.
| Attribute | Outcome | Notes |
|---|---|---|
| address_type | Converted | EXTERNAL (or unset) becomes a public IP; INTERNAL blocks the conversion. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| address | Manual action required | a specific reserved address cannot be requested; the platform allocates the address. |
| region | Converted | Frostmoln is single-region today; the platform default region applies. |
| network_tier | Not carried over | network service tiers (PREMIUM/STANDARD) have no equivalent. |
| purpose | Not carried over | special address purposes (VPC_PEERING, PSC) have no equivalent. |
| subnetwork | Not needed on Frostmoln | public IPs are not scoped to a subnet. |
| prefix_length | Manual action required | address ranges (prefixes) have no equivalent; the platform allocates a single address. |
| ip_version | Manual action required | IPv6 addressing is not supported yet. |
| name | Not carried over | frostmoln_public_ip has no name. |
| description | Not carried over | frostmoln_public_ip has no description. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
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.
| Attribute | Outcome | Notes |
|---|---|---|
| disk | Mapped to volume_id | |
| instance | Mapped to instance_id | |
| device_name | Mapped to device_path | |
| mode | Not carried over | read-only attachments are not supported; attachments are read-write. |
| zone | Not needed on Frostmoln | the platform infers the zone from the volume and instance. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| description | Mapped to description | |
| size | Mapped to size_gb | |
| type | Not carried over | volume tiers are platform-defined; the default tier applies — pick a volume_type from the volume tiers catalog to change it. |
| zone | Converted | The platform picks the zone; set zone to a zone id to pin one. |
| snapshot | Converted to snapshot_id | A direct google_compute_snapshot reference is rewritten to the converted frostmoln_snapshot id; otherwise set snapshot_id manually. |
| image | Manual action required | creating a disk from an image has no equivalent; boot instances from a frostmoln_image instead. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| physical_block_size_bytes | Not carried over | the physical block size is platform-managed. |
| provisioned_iops | Not carried over | IOPS are set by the volume tier. |
| provisioned_throughput | Not carried over | throughput is set by the volume tier. |
| disk_encryption_key | Manual action required | customer-managed disk encryption keys have no equivalent; volumes are encrypted with platform-managed keys. |
| source_snapshot_encryption_key | Manual action required | customer-managed encryption keys have no equivalent. |
| source_image_encryption_key | Manual action required | customer-managed encryption keys have no equivalent. |
| guest_os_features | Not carried over | guest OS features are determined by the instance image. |
| interface (retired by the provider) | Not carried over | the disk interface (SCSI/NVME) is platform-managed. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
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 (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, 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Converted | becomes the generated frostmoln_security_group name. |
| network | Converted | a direct google_compute_network reference becomes vpc_id on the generated security group. |
| direction | Converted | INGRESS/EGRESS becomes the direction of each generated rule. |
| source_ranges | Converted | the ingress source CIDRs become remote_cidr on the generated rules (fanned out). |
| destination_ranges | Converted | the egress destination CIDRs become remote_cidr on the generated rules (fanned out). |
| allow | Converted | each allow protocol/port becomes one or more frostmoln_security_group_rule resources. |
| deny | Manual action required | deny rules have no equivalent — the platform is allow-only, so a converted deny rule would OPEN the traffic it denies. Remove the deny firewall and tighten the allow rules instead. |
| target_tags | Manual action required | target_tags select instances by tag; the converter does not guess instance membership. Attach the generated frostmoln_security_group to those instances (frostmoln_instance.security_groups) manually. |
| target_service_accounts | Manual action required | target_service_accounts select instances by identity; attach the generated frostmoln_security_group to those instances manually. |
| source_tags | Manual action required | tag-scoped sources have no equivalent; recreate the rule with explicit source CIDRs. |
| source_service_accounts | Manual action required | identity-scoped sources have no equivalent; recreate the rule with explicit source CIDRs. |
| priority | Not carried over | the platform does not order rules; allow-only rules are additive and order-independent. |
| disabled | Manual action required | a disabled firewall converted to active rules would widen access; remove it or recreate the intended rules explicitly. |
| log_config | Not carried over | firewall logging is platform-managed; use the platform's observability. |
| description | Converted | The firewall's description becomes the generated frostmoln_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. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
| params | Not carried over | params.resource_manager_tags binds GCP organization tag keys and values by id (tagKeys/... = tagValues/...), which mean nothing outside that organization, so the bindings are not carried onto the generated frostmoln_security_group. Add the key/value pairs you need as tags on the generated security group. |
google_compute_forwarding_rule → frostmoln_load_balancer — partially supported
Forwarding rules map to the frontend of a frostmoln_load_balancer (an l4 load balancer); 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| load_balancing_scheme | Converted to scheme | A public scheme requires a public_ip_id — create a frostmoln_public_ip for the load balancer. |
| network | Converted to vpc_id | A direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually. |
| subnetwork | Converted to subnet_id | A direct google_compute_subnetwork reference is rewritten to the converted frostmoln_subnet id; otherwise set subnet_id manually. |
| ip_protocol | Not carried over | the L4 protocol is set on the frostmoln_lb_listener, not the load balancer. |
| port_range | Not carried over | the listening port is set on the frostmoln_lb_listener (protocol_port); create one for this load balancer. |
| ports | Not carried over | the listening ports are set on the frostmoln_lb_listener (protocol_port); create one per port. |
| all_ports | Manual action required | forwarding all ports has no equivalent; create a frostmoln_lb_listener per port. |
| target | Manual action required | the backend is a separate resource on Frostmoln; create a frostmoln_lb_pool from the target_pool and set load_balancer_id to this load balancer. |
| backend_service | Manual action required | backend services (L7 / managed L4) are not supported; recreate the pool and members manually. |
| ip_address | Manual action required | a specific frontend address cannot be requested; use public_ip_id (a frostmoln_public_ip) for a public address. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| region | Converted | Frostmoln is single-region today; the platform default region applies. |
| allow_global_access | Not carried over | global access has no equivalent; the platform is single-region. |
| network_tier | Not carried over | network service tiers have no equivalent. |
| service_label | Not carried over | internal DNS service labels have no equivalent. |
| description | Not carried over | frostmoln_load_balancer has no description on the forwarding-rule frontend. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
typeautomatically. a network forwarding rule is an L4 load balancer (type = l4); change it to l7 for a Layer 7 load balancer. - The converter adds
vpc_idautomatically. frostmoln_load_balancer requires a VPC; set vpc_id to the converted frostmoln_vpc id. - The converter adds
subnet_idautomatically. 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.
| Attribute | Outcome | Notes |
|---|---|---|
| check_interval_sec | Mapped to delay | |
| timeout_sec | 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. |
| tcp_health_check | Converted to type | becomes type = "tcp"; the port is set per member. |
| http_health_check | Converted to type | becomes type = "http" with url_path from request_path; the port is set per member. |
| https_health_check | Converted to type | becomes type = "https" with url_path from request_path; the port is set per member. |
| ssl_health_check | Manual action required | SSL (raw TLS) health checks have no equivalent; use a tcp or https health check. |
| http2_health_check | Manual action required | HTTP/2 health checks have no equivalent; use an http or https health check. |
| grpc_health_check | Manual action required | gRPC health checks have no equivalent; use a tcp health check. |
| name | Not carried over | frostmoln_lb_health_monitor has no name. |
| description | Not carried over | frostmoln_lb_health_monitor has no description. |
| log_config | Not carried over | health-check logging is platform-managed. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
typeautomatically. 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_idautomatically. frostmoln_lb_health_monitor requires load_balancer_id; set it to the converted load balancer. - The converter adds
pool_idautomatically. 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 (instances carry no ambient identity; give the instance an API key granted by a frostmoln_iam_policy). Preemptible/spot scheduling and shielded-VM settings are dropped.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| machine_type | Converted to flavor_id | Parsed algorithmically into vCPUs/RAM and capability-matched against the platform flavor catalog, emitted as a frostmoln_flavor data source lookup. |
| zone | Converted | The platform picks the zone; set zone to a zone id to pin one. |
| boot_disk | Converted to image_id | initialize_params.image becomes image_id (a frostmoln_image lookup); the disk size and type are dropped (the flavor and platform tier determine them). |
| network_interface | Converted | subnetwork becomes subnet_id, network becomes vpc_id, and an access_config (external IP) becomes a generated frostmoln_public_ip bound to the instance. |
| metadata | Converted to ssh_key_names | SSH 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_script | Mapped to user_data | The startup script becomes plain-text user_data. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| tags | Not carried over | GCP NETWORK tags are firewall selectors, NOT frostmoln tags — mapping them to tags would be silently wrong. The firewall→security_group conversion notes which instances need the generated group; attach it via security_groups. |
| service_account | Manual action required | instances carry no ambient cloud identity — a Frostmoln instance has no attached identity to impersonate, so instance identity does not carry over. Give the instance a frostmoln_api_key (or a frostmoln_s3_credential for bucket access) and grant it what the service account's roles granted with a frostmoln_iam_policy attached via frostmoln_iam_policy_attachment. Dropping this silently could imply broader access than intended. |
| scheduling | Not carried over | preemptible/spot scheduling has no equivalent; instances are always standard (on-demand). |
| shielded_instance_config | Not carried over | shielded-VM settings (secure boot, vTPM, integrity monitoring) are platform-managed. |
| confidential_instance_config | Not carried over | confidential computing has no equivalent. |
| can_ip_forward | Not carried over | Not carried over: there is no per-instance forwarding flag. An instance forwards only while a frostmoln_vpc_route names its address as the next hop, and that route also lets it source addresses it does not own. Read the cost in the VPC routes documentation first. |
| deletion_protection | Not carried over | deletion protection is not supported. |
| allow_stopping_for_update | Not needed on Frostmoln | update behavior is platform-managed. |
| attached_disk | Manual action required | inline attached disks are not supported; recreate them as frostmoln_volume + frostmoln_volume_attachment. |
| guest_accelerator | Manual action required | GPUs / accelerators have no equivalent. |
| min_cpu_platform | Not carried over | CPU platform pinning is not supported; the flavor defines the CPU. |
| resource_policies | Manual action required | resource policies (scheduling, placement) have no equivalent. |
| advanced_machine_features | Not carried over | advanced machine features (nested virtualization, threads-per-core) have no equivalent. |
| reservation_affinity | Not carried over | capacity reservations are not supported. |
| enable_display | Not carried over | the virtual display device has no equivalent. |
| hostname | Not carried over | the instance hostname is platform-managed. |
| description | Not carried over | frostmoln_instance has no description. |
| desired_status | Not carried over | instance power state is managed outside the resource. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
flavor_idautomatically. frostmoln_instance requires a flavor; set flavor_id to a platform flavor (seefm compute flavor list). - The converter adds
image_idautomatically. frostmoln_instance requires an image; set image_id to a platform image (seefm 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| project | Manual action required | project scoping has no equivalent; look the VPC up by name. |
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 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). A google_compute_router_nat in the source configuration does not convert into one — see its entry.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| description | Mapped to description | |
| auto_create_subnetworks | Not carried over | auto-mode subnets are created by GCP automatically and have no Terraform resource; recreate the subnets you need as frostmoln_subnet. |
| routing_mode | Not carried over | routing mode (regional/global) is platform-managed. |
| mtu | Not carried over | the MTU is platform-managed. |
| delete_default_routes_on_create | Not carried over | default routes are platform-managed. |
| network_firewall_policy_enforcement_order | Not carried over | firewall-policy ordering has no equivalent (the platform is allow-only). |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
cidrautomatically. 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_route → frostmoln_vpc_route — partially supported
a route whose next hop is an address or an instance becomes a frostmoln_vpc_route on the converted VPC — next_hop_ip carries over as-is, next_hop_instance is left as a placeholder address to fill in — while gateway, ILB and VPN-tunnel next hops, tag-scoped routes and IPv6 default routes are left unconverted.
A Frostmoln VPC has ONE route set and it belongs to the VPC, so a converted route applies to every instance in it.
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.
The network reference becomes vpc_id when network points at a google_compute_network in the same configuration. Any other form — a bare network name, a self_link, a variable — is kept and flagged for review: it is not a VPC id, and applying it unchanged will not find your VPC.
next_hop_ip is already an address and carries over unchanged. next_hop_instance is not: a Frostmoln next hop is an IP ADDRESS on a subnet attached to the VPC (or the reserved token internet), never a resource id, so such a route converts with its destination intact and next_hop left as an FM-TODO placeholder — set it to the instance'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 with tags is left UNCONVERTED. GCP applies a tagged route to the tagged instances only; a Frostmoln route is matched on its DESTINATION alone — a VPC router has no per-source routing — so converting one would silently widen it to every instance in the VPC.
A route with next_hop_ilb or next_hop_vpn_tunnel is left UNCONVERTED: the platform has no equivalent, and a route that quietly sends the same traffic somewhere else is worse than no route.
next_hop_gateway is left unconverted too, but for two different reasons depending on the destination, and ONE OF THEM HAS A COUNTERPART. A route sending a SPECIFIC destination out the 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 to default-internet-gateway is the other case: nothing needs writing, because the VPC's own gateway already provides it and writing one is refused. The gateway itself is not implied, though — 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 google_compute_router_nat 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, 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. An IPv6 default route (::/0) is NOT offered and is refused.
Route priority does not carry over. Selection is by destination prefix length, so a more specific route wins — but two routes with the SAME destination and different priorities, the GCP way of writing a primary and a backup next hop, cannot both exist: the platform refuses the second as a duplicate. Decide which one you want before you apply. 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 |
|---|---|---|
| dest_range | 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 IPv4 default route is flagged, because it captures all egress from the VPC (one built from a variable cannot be read, so it is not); an IPv6 default route (::/0) and a default-route half (0.0.0.0/1, 128.0.0.0/1) leave the WHOLE route unconverted, because the platform offers neither. |
| network | Converted to vpc_id | A direct google_compute_network reference becomes the converted frostmoln_vpc id; any other form — a bare network NAME, a self_link, a variable — is kept and flagged for review, because it is not a VPC id. |
| next_hop_ip | Mapped to next_hop | Already an address, so it carries over unchanged; it must be reachable from a subnet attached to the VPC. |
| next_hop_instance | 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. |
| next_hop_instance_zone | Not carried over | the next hop is an address, so the instance's zone is not part of it. |
| next_hop_gateway | Manual action required | Left unconverted, because the two shapes convert differently. A DEFAULT route out the gateway needs no route at all — the VPC's frostmoln_gateway provides it. A SPECIFIC destination out the gateway is written as next_hop = internet, which is how the exception route a forced tunnel needs is expressed. |
| next_hop_ilb | Manual action required | Left unconverted: an internal load balancer as a next hop has no equivalent. |
| next_hop_vpn_tunnel | Manual action required | Left unconverted: Cloud VPN tunnels have no equivalent. Run your own VPN appliance in the VPC and point the route at its address. |
| tags | Manual action required | Left unconverted: a Frostmoln route is matched on its destination only, so it applies to every instance in the VPC. Converting a tag-scoped route would silently widen it. |
| priority | Not carried over | There is no priority. A more specific destination wins; two routes with the same destination cannot coexist, so a primary/backup pair ordered by priority has to be reduced to one. |
| name | Not carried over | a route has no name; it is identified by its destination within the VPC. |
| description | Not carried over | a route has no description. |
| deletion_policy | Not carried over | there is no per-route deletion policy. |
| params | Not carried over | resource-manager tags have no equivalent. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- 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.
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).
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| description | Mapped to description | |
| source_disk | Converted to volume_id | A direct google_compute_disk reference is rewritten to the converted frostmoln_volume id; otherwise set volume_id manually. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| zone | Not needed on Frostmoln | the platform infers the zone from the source volume. |
| storage_locations | Not carried over | snapshot storage locations are platform-managed. |
| snapshot_encryption_key | Manual action required | customer-managed encryption keys have no equivalent; snapshots are encrypted with platform-managed keys. |
| source_disk_encryption_key | Manual action required | customer-managed encryption keys have no equivalent. |
| chain_name | Not carried over | snapshot chains are platform-managed. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
volume_idautomatically. 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).
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| region | Manual action required | region scoping has no equivalent; look the subnet up by name. |
| project | Manual action required | project scoping has no equivalent; look the subnet up by name. |
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).
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| description | Mapped to description | |
| ip_cidr_range | Mapped to cidr | |
| network | Converted to vpc_id | A direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually. |
| region | Converted | The platform picks the zone; set zone to a zone id to pin one. |
| secondary_ip_range | Not carried over | alias-IP secondary ranges have no equivalent; recreate them manually if needed. |
| private_ip_google_access | Not carried over | Private Google Access is a GCP-specific egress feature with no equivalent. |
| private_ipv6_google_access | Not carried over | Private Google Access is a GCP-specific egress feature with no equivalent. |
| purpose | Not carried over | special-purpose subnets (proxy-only, PSC, private-NAT) have no equivalent. |
| role | Not carried over | the ACTIVE/BACKUP role (for proxy-only subnets) has no equivalent. |
| log_config | Not carried over | VPC flow logs are platform-managed; use the platform's observability. |
| stack_type | Not carried over | IPv4/IPv6 stack selection is platform-managed (IPv4 today). |
| ipv6_access_type | Manual action required | IPv6 subnets are not supported yet. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
vpc_idautomatically. 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 an l4 load balancer supports only source_ip_port, so change lb_algorithm when attaching this pool to an l4 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| instances | Manual action required | pool members are separate resources; recreate one frostmoln_lb_member per backend, using the instance's private IP as address. |
| health_checks | Manual action required | the health check is a separate frostmoln_lb_health_monitor; create one and set its pool_id to this pool. |
| session_affinity | Not carried over | session affinity becomes the session_persistence block; recreate session_persistence = { type = "SOURCE_IP" } manually if you used CLIENT_IP affinity. |
| backup_pool | Manual action required | backup pools (failover) have no equivalent. |
| failover_ratio | Not carried over | failover ratios have no equivalent. |
| region | Converted | Frostmoln is single-region today; the platform default region applies. |
| description | Not carried over | frostmoln_lb_pool has no description. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
protocolautomatically. 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_algorithmautomatically. frostmoln_lb_pool requires lb_algorithm; an l4 load balancer supports only source_ip_port — change it when attaching to an l4 load balancer. - The converter adds
load_balancer_idautomatically. 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 the optional workload-identity cluster add-on (add it to addons, at create or later) rather than a cluster flag, so workload_identity_config carries nothing over. 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| min_master_version | Mapped to version | Verify the version is offered on the platform (fm kubernetes version list). |
| network | Converted to vpc_id | A direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually. |
| subnetwork | Converted to subnet_id | A direct google_compute_subnetwork reference is rewritten to the converted frostmoln_subnet id; otherwise set subnet_id manually. |
| node_config | Converted to initial_node_pool | The 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_config | Not carried over | The 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_count | Not needed on Frostmoln | consumed into initial_node_pool.node_count. |
| remove_default_node_pool | Not needed on Frostmoln | the GKE default-pool bootstrap quirk has no equivalent; define node pools as frostmoln_kubernetes_node_pool. |
| master_authorized_networks_config | Not carried over | master authorized networks have no equivalent. The API endpoint is not publicly exposed on the platform in the first place, so the risk they mitigate does not arise; use network policy for in-cluster restrictions. |
| workload_identity_config | Not carried over | Workload identity is available on managed Kubernetes as the optional workload-identity cluster add-on rather than a cluster flag, so there is nothing to configure here. Add workload-identity to the frostmoln_kubernetes_cluster addons set, when the cluster is created or later (it is applied in place to a running cluster). 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_channel | Not carried over | release channels are platform-managed; pin a version instead. |
| addons_config | Not carried over | GKE add-ons are platform-managed; use the platform's addons. |
| network_policy | Not carried over | the network-policy provider (Calico) is platform-managed. |
| ip_allocation_policy | Not carried over | the pod and service CIDRs are platform-managed. |
| enable_autopilot | Manual action required | Autopilot clusters have no equivalent. |
| cluster_autoscaling | Manual action required | cluster autoscaling has no equivalent; use fixed node pools. |
| logging_service | Not carried over | logging is platform-managed; use the platform's observability. |
| monitoring_service | Not carried over | monitoring is platform-managed; use the platform's observability. |
| logging_config | Not carried over | logging is platform-managed. |
| monitoring_config | Not carried over | monitoring is platform-managed. |
| maintenance_policy | Not carried over | maintenance windows are platform-managed. |
| location | Not needed on Frostmoln | the platform is single-region; the default region applies. |
| node_locations | Not carried over | node zones are platform-managed. |
| resource_labels | Converted to tags | Resource labels become frostmoln tags (at most 32 per resource, your tenant's default tags included). They are cluster tags, never Kubernetes node labels; the initial node pool gets a one-time copy at create. |
| deletion_protection | Not carried over | deletion protection is not supported. |
| datapath_provider | Not carried over | the datapath (Dataplane V2 / Cilium) is platform-managed. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
initial_node_poolautomatically. frostmoln_kubernetes_cluster requires an initial node pool; set flavor_id to a platform flavor (seefm kubernetes flavor list) — the real pools convert to frostmoln_kubernetes_node_pool. - The converter adds
versionautomatically. frostmoln_kubernetes_cluster requires a version; set it to an offered version (fm kubernetes version list). - The converter adds
vpc_idautomatically. frostmoln_kubernetes_cluster requires a VPC; set vpc_id to the converted frostmoln_vpc id. - The converter adds
subnet_idautomatically. 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | The pool name must be a lowercase DNS label of at most 18 characters. |
| cluster | Converted to cluster_id | A direct google_container_cluster reference is rewritten to the converted frostmoln_kubernetes_cluster id. |
| node_config | Converted to flavor_id | node_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_count | Mapped to node_count | |
| autoscaling | Manual action required | cluster autoscaling has no equivalent; set a fixed node_count. |
| initial_node_count | Not needed on Frostmoln | node_count is the source of truth; the initial count is not separately tracked. |
| management | Not carried over | auto-repair/auto-upgrade are platform-managed. |
| upgrade_settings | Not carried over | surge/blue-green upgrade settings are platform-managed. |
| max_pods_per_node | Not carried over | the pod density is platform-managed. |
| node_locations | Not carried over | node zones are platform-managed. |
| location | Not needed on Frostmoln | the platform is single-region; the default region applies. |
| version | Not carried over | the node Kubernetes version follows the cluster version. |
| network_config | Not carried over | per-pool network config has no equivalent. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
flavor_idautomatically. frostmoln_kubernetes_node_pool requires a flavor; set flavor_id to a platform flavor (seefm 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.
| Attribute | Outcome | Notes |
|---|---|---|
| dns_name | Converted to name | Normalized to a lowercase fully qualified domain with a trailing dot, e.g. "example.com." |
| name | Not carried over | the zone name IS the domain on Frostmoln; the GCP resource name has no equivalent. |
| description | Mapped to description | |
| visibility | Converted | public zones convert; a private zone blocks the conversion. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| dnssec_config | Not carried over | DNSSEC configuration is platform-managed. |
| private_visibility_config | Manual action required | private (split-horizon) zones have no equivalent; only public zones convert. |
| forwarding_config | Manual action required | DNS forwarding has no equivalent. |
| peering_config | Manual action required | DNS peering has no equivalent. |
| cloud_logging_config | Not carried over | DNS query logging is platform-managed. |
| force_destroy | Not needed on Frostmoln | zones are deleted with their records. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
emailautomatically. 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Converted | Record names are zone-relative; a name referencing an in-config zone's dns_name is stripped automatically. |
| managed_zone | Converted to zone_id | A direct google_dns_managed_zone reference is rewritten to the converted frostmoln_dns_zone id. |
| type | Converted | Supported types carry over; SOA and other types have no equivalent (SOA is platform-managed). |
| rrdatas | Mapped to records | The record data list becomes the records set. |
| ttl | Mapped to ttl | |
| routing_policy | Manual action required | weighted/geo/failover routing policies have no equivalent; use a simple record with explicit values. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| redis_version | Converted to version | REDIS_7_0 becomes "7"; verify the version is offered (fm cache redis version list). |
| authorized_network | Converted to vpc_id | A direct google_compute_network reference is rewritten to the converted frostmoln_vpc id; otherwise set vpc_id manually. |
| memory_size_gb | Not carried over | the GCP memory size does not map to a platform flavor; set flavor_id to the flavor whose memory tier matches. |
| tier | Not carried over | the GCP tier (BASIC/STANDARD_HA) has no direct equivalent; STANDARD_HA high-availability is not exposed on frostmoln_redis_instance. |
| redis_configs | Not carried over | set eviction_policy (from maxmemory-policy) and persistence_mode on the instance manually. |
| reserved_ip_range | Manual action required | static IP ranges are not supported; the platform assigns one. |
| connect_mode | Not carried over | the connection mode (direct peering / private service access) is platform-managed. |
| transit_encryption_mode | Converted | DISABLED 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_enabled | Not needed on Frostmoln | authentication is always enforced and platform-managed — the platform issues an AUTH password whether or not the source enabled one. Note it crosses the wire in cleartext, because there is no TLS listener. |
| replica_count | Not carried over | read replicas have no equivalent yet. |
| read_replicas_mode | Not carried over | read replicas have no equivalent yet. |
| labels | Converted to tags | GCP labels become frostmoln tags (at most 32 per resource, your tenant's default tags included). |
| region | Not needed on Frostmoln | the platform is single-region; the default region applies. |
| location_id | Not carried over | the platform picks the zone. |
| alternative_location_id | Not carried over | the platform picks the zone. |
| maintenance_policy | Not carried over | maintenance windows are platform-managed. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
versionautomatically. frostmoln_redis_instance requires a version; set it to an offered version (fm cache redis version list). - The converter adds
flavor_idautomatically. frostmoln_redis_instance requires a flavor; the GCP memory size does not map — set flavor_id (seefm cache flavor list). - The converter adds
vpc_idautomatically. frostmoln_redis_instance requires a VPC; set vpc_id to the converted frostmoln_vpc id. - The converter adds
subnet_idautomatically. 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.
| Attribute | Outcome | Notes |
|---|---|---|
| secret_id | Mapped to name | |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| replication | Not needed on Frostmoln | replication is platform-managed; data is stored in the single EU region. |
| rotation | Not carried over | automatic rotation schedules have no equivalent; rotate secrets explicitly. |
| topics | Not carried over | Pub/Sub rotation notifications have no equivalent. |
| ttl | Not carried over | secret TTL has no equivalent. |
| expire_time | Not carried over | secret expiry has no equivalent; rotate secrets explicitly. |
| version_aliases | Not carried over | version aliases are platform-managed. |
| annotations | Not carried over | secret annotations have no equivalent. |
| secret_type | Not carried over | secret types (structural requirements enforced on secret versions) have no equivalent; frostmoln_secret stores the value as-is, so validate its format yourself. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
secret_valueautomatically. 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 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, settings.availability_type = REGIONAL becomes ha_enabled, and settings.user_labels become the instance's tags (at most 32, your tenant's default tags included). 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.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| database_version | Converted to version | POSTGRES_16 becomes "16"; a MYSQL_* version blocks (use frostmoln_mysql_instance). |
| settings | Converted | disk_size becomes storage_gb, availability_type REGIONAL becomes ha_enabled and user_labels become tags; 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_name | Manual action required | this is a read replica; recreate it as a frostmoln_postgres_read_replica (set master_instance_id to the primary). |
| replica_configuration | Manual action required | replica configuration has no equivalent; recreate read replicas as frostmoln_postgres_read_replica. |
| root_password | Not carried over | the admin password is platform-issued. |
| region | Not needed on Frostmoln | the platform is single-region; the default region applies. |
| deletion_protection | Not carried over | deletion protection is not supported. |
| encryption_key_name | Manual action required | customer-managed encryption keys have no equivalent. |
| instance_type | Not carried over | the Cloud SQL instance type (regular/read-replica) is inferred from the resource. |
| maintenance_version | Not carried over | the maintenance version is platform-managed. |
| encryption_confidential_mode | Not carried over | confidential computing has no equivalent. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
versionautomatically. frostmoln_postgres_instance requires a version; set it to an offered version (fm database postgres version list). - The converter adds
vpc_idautomatically. 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_idautomatically. 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, lifecycle and CORS are separate Frostmoln resources you recreate alongside it, and bucket-level IAM 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 and CORS are their own resources on Frostmoln — frostmoln_bucket_lifecycle_configuration and frostmoln_bucket_cors_configuration — and the converter does not generate them, so recreate them yourself. Website hosting and retention policies have no equivalent.
| Attribute | Outcome | Notes |
|---|---|---|
| name | Mapped to name | |
| location | Converted | Frostmoln is single-region today; the platform default region applies. |
| versioning | Converted | versioning.enabled = true becomes versioning = "enabled"; false becomes "suspended". |
| storage_class | Not carried over | the platform storage class applies; set storage_class after conversion if a non-default class is needed. |
| labels | Converted to tags | GCP labels become frostmoln tags. |
| uniform_bucket_level_access | Not needed on Frostmoln | buckets are private with uniform access by default; there is no ACL mode toggle. |
| public_access_prevention | Not carried over | buckets are private by default; public access is not available. |
| 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 and per-object-tag filters have no counterpart; scope a rule by prefix. |
| cors | 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. |
| website | Manual action required | static-website hosting is not available. |
| encryption | Not needed on Frostmoln | objects are always encrypted at rest; encryption is not configurable. |
| logging | Not carried over | bucket access logging is not yet configurable. |
| retention_policy | Manual action required | object retention (WORM) is not available. |
| autoclass | Not carried over | automatic storage-class transitions have no equivalent. |
| requester_pays | Not needed on Frostmoln | there is no requester-pays billing concept. |
| force_destroy | Not needed on Frostmoln | bucket deletion behavior is platform-defined. |
| default_event_based_hold | Manual action required | event-based holds have no equivalent. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
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.
| Attribute | Outcome | Notes |
|---|---|---|
| service_account_email | Not carried over | HMAC keys are scoped to a service account; Frostmoln S3 credentials are scoped to buckets/actions — set allowed_buckets / allowed_actions instead. |
| state | Not carried over | the key state (ACTIVE/INACTIVE) is managed outside the resource. |
| project | Not needed on Frostmoln | there is no project concept; resources are tenant-scoped. |
- The converter adds
nameautomatically. frostmoln_s3_credential requires a name; it is taken from the resource address.
Resources the converter does not convert
| Resource | What happens |
|---|---|
| google_bigquery_dataset | BigQuery has no equivalent; run analytics on a managed PostgreSQL/MySQL instance or a self-hosted database. |
| google_cloud_run_service | Managed container serverless (Cloud Run) has no equivalent; deploy containers on frostmoln_kubernetes_cluster. |
| google_cloudfunctions_function | Serverless functions have no equivalent; run code on a frostmoln_instance or in frostmoln_kubernetes_cluster. |
| google_compute_backend_service | Backend services do not convert directly. For an L4 load balancer, convert the forwarding rule and target pool instead; for an L7 one, the Frostmoln equivalent is a frostmoln_appgw_backend_pool on a frostmoln_application_gateway. |
| google_compute_network_peering | VPC network peering has no equivalent; connect workloads within a single VPC. |
| google_compute_router | Dynamic routing has no equivalent and Cloud Routers are removed (static routes DO convert — see google_compute_route); 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_nat | 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 Cloud NATs serving one network collapse into a single gateway. |
| google_compute_router_nat_address | A 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_security_policy | Frostmoln has a Web Application Firewall, but it is part of an Application Gateway rather than a standalone policy attached to a backend service, so a security policy does not convert on its own — recreate it as a frostmoln_appgw_waf_policy on the gateway that fronts the same traffic. |
| google_compute_url_map | URL maps do not convert, but host and path routing DOES exist on Frostmoln — as an Application Gateway, not a load balancer. Rebuild the map as frostmoln_appgw_route resources on a frostmoln_application_gateway. |
| google_compute_vpn_gateway | Cloud VPN gateways have no equivalent; terminate site-to-site VPNs on a customer-managed instance. |
| google_kms_crypto_key | Customer-managed encryption keys have no equivalent; resources are encrypted with platform-managed keys. |
| google_project_iam_member | There are no project-level IAM bindings; attach a frostmoln_iam_policy to the principal instead. |
| google_pubsub_subscription | Pub/Sub has no equivalent; Frostmoln's managed message broker speaks AMQP (LavinMQ), not Pub/Sub. |
| google_pubsub_topic | Pub/Sub has no equivalent; Frostmoln's managed message broker speaks AMQP (LavinMQ), not Pub/Sub. |
| google_secret_manager_secret_version | Secret versions have no standalone equivalent; the value is set on the frostmoln_secret directly. |
| google_service_account | There 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_database | Databases are created inside the managed instance; a standalone database resource has no equivalent. |
| google_sql_user | Database users are managed inside the instance; a standalone user resource has no equivalent. |
| google_storage_bucket_object | Individual 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 database 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
Two different answers depending on which load balancer this backs.
L4 — convert the network load balancer (google_compute_forwarding_rule + google_compute_target_pool) to a frostmoln_load_balancer with its frostmoln_lb_listener, frostmoln_lb_pool and frostmoln_lb_member.
L7 — host and path routing exists on Frostmoln as an Application Gateway, not as a load-balancer feature. A backend service becomes a frostmoln_appgw_backend_pool with one frostmoln_appgw_backend per instance address, targeted by frostmoln_appgw_route resources that carry the host and path. Health checks become a frostmoln_appgw_health_check on the pool.
The converter does not do that translation: a backend service is joined to its URL map, target proxy and forwarding rule by name across several resources, and following those references is not something this conversion attempts. Rebuild it by hand — the azurerm_application_gateway mapping is the worked example of the shape.
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_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 reach to that control plane 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 reach to that control plane 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_security_policy
This entry exists so the firewall is REPORTED rather than silently dropped. A security policy 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 policy 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; - the preconfigured WAF rule expressions 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 expression by expression, and its version is read (managed_ruleset_version), not written;
- each of your own match rules is a frostmoln_appgw_waf_rule with kind = "builder" and a builder_json condition set. Conditions are matched with RE2 regular expressions and a fixed operator set, not an expression language, so a rule written as a CEL expression has to be restated;
- an opt-out of one preconfigured rule 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;
- attaching the policy to a backend service is a frostmoln_appgw_waf_policy_attachment.
What does not map: rate-limiting and throttle actions (per-source rate limiting is rate_limit_rps and rate_limit_burst on a frostmoln_appgw_listener, not a WAF rule), adaptive protection, reCAPTCHA actions, and edge and network-policy types. An IP allow- or deny-list rule is better expressed as allowed_cidrs, denied_cidrs or geo_block_mode on a frostmoln_appgw_listener than as a firewall rule.
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.
google_compute_url_map
THIS IS NOT A MISSING CAPABILITY, IT IS A DIFFERENT RESOURCE. A Frostmoln load balancer distributes; host and path routing is what a frostmoln_application_gateway does. Each path_matcher rule becomes a frostmoln_appgw_route with host, path and path_match_type (prefix, exact or regex) pointing at a frostmoln_appgw_backend_pool, behind a frostmoln_appgw_listener.
The converter does not do that translation for you — a URL map is joined to its backend services, target proxy and forwarding rule by name across several resources, and following those references is not something this conversion attempts. Rebuild the routing by hand, and note that nothing the gateway is told is served until a frostmoln_appgw_config_apply dispatches it. The azurerm_application_gateway mapping is the worked example of the shape.
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.