frostmoln_public_ip (Resource)
Manages a public IP in the Frostmoln Cloud Platform.
Destroying this resource RELEASES THE ADDRESS, and the address does not come back. It returns to a shared regional pool and is re-issued to whoever asks for one next — possibly another tenant, within minutes. Anything that named it stops matching: a partner's allow-list entry, a DNS record, a firewall rule at the other end.
There is no undo and no support request that recovers it, so an address anyone else depends on is worth protecting in the configuration itself with Terraform's own lifecycle { prevent_destroy = true } — see the example below. It fails the PLAN, so a module removal, a terraform destroy -target, or CI running terraform destroy -auto-approve stops before anything is sent. This provider additionally refuses to release an address that is serving a VPC's outbound path unless acknowledge_address_loss = true — see that attribute.
~> frostmoln_public_ip.instance_id and the frostmoln_public_ip_association resource are mutually exclusive — never use both for the same address. Both express the SAME attachment, so both would manage it: whichever applies second undoes what the first did, every subsequent plan proposes the change again, and the configuration never converges. (It is the same conflict the AWS provider documents between aws_eip.instance and aws_eip_association.)
Pick one per address. Use frostmoln_public_ip.instance_id when the SAME configuration allocates the address, so the address and its attachment are created and destroyed together.
Use frostmoln_public_ip_association when the address ALREADY EXISTS (look it up with the frostmoln_public_ip data source), or when it has to outlive the instance it is attached to. Destroying that resource detaches the address and leaves it allocated to your tenant, whereas destroying a frostmoln_public_ip RELEASES the address for good.
Example Usage
# A public IP attached to an instance. Destroying this releases the address.
#
# `instance_id` is what makes the ATTACHMENT here, and an attached address
# depends on the VPC having a gateway — which Terraform cannot see, because
# nothing in this resource refers to frostmoln_gateway. Left unordered the two
# run concurrently: on teardown the gateway can go first and its delete is
# refused ("Gateway is still in use", GATEWAY_IN_USE), and on create the
# attachment can land first, after which the platform attaches a gateway itself
# and an explicit one either collides with it (GATEWAY_EXISTS, if it pins a
# public_ip_id) or silently adopts it. depends_on states the order; it creates
# and releases nothing.
resource "frostmoln_public_ip" "example" {
instance_id = frostmoln_instance.example.id
tags = {
service = "web"
}
depends_on = [frostmoln_gateway.partner_facing]
}
# AN ADDRESS SOMEONE ELSE DEPENDS ON — one in a partner's allow-list, published
# in DNS, or serving a VPC's outbound path — is worth protecting in the configuration
# itself.
#
# Destroying this resource RELEASES THE ADDRESS.
#
# The address does not come back: it returns to a shared regional pool and is
# re-issued to whoever asks for one next, possibly another tenant, within
# minutes. Re-running `terraform apply` does not restore it — it allocates a
# different one. There is no undo and no support request that recovers it.
#
# `prevent_destroy` is Terraform's own guard and the strongest one available,
# because it fails the PLAN. A module removal, a `terraform destroy -target`, or
# CI running `terraform destroy -auto-approve` all stop before anything is sent.
#
# To retire the address deliberately: remove the lifecycle block, apply, then
# destroy.
resource "frostmoln_public_ip" "partner_facing" {
tags = {
purpose = "partner allow-list"
}
lifecycle {
prevent_destroy = true
}
}
# This address is the VPC's outbound source address, so the whole VPC's traffic
# arrives from it. See frostmoln_gateway.
#
# NOTE THE ASYMMETRY WITH THE ADDRESS ABOVE. This one is NAMED by the gateway, so
# the gateway already depends on it and Terraform already sequences the two
# correctly — allocate first, and on teardown detach the gateway before the
# address is released. Adding a depends_on back to the gateway here would be a
# plan-time `Cycle:` error. The ordering above is needed only because an ATTACHED
# address has no such reference to derive the dependency from.
resource "frostmoln_gateway" "partner_facing" {
vpc_id = frostmoln_vpc.example.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.partner_facing.id
}
# The provider ALSO refuses to release an address that is serving a VPC's outbound path
# unless the intent is stated:
#
# acknowledge_address_loss = true
#
# That check reads the recorded attachment, so it still fires in the case the
# platform itself cannot catch: because the gateway above refers to this
# address, `terraform destroy` destroys the gateway first, the platform hands
# the address back as an ordinary unattached address, and the release that
# follows looks — to the platform — like the release of something idle.
#
# Add the line, apply it, destroy, and then REMOVE IT AGAIN. It is ordinary
# configuration, so a `true` left behind disarms the check for the rest of the
# resource's life. It is not a substitute for `prevent_destroy`, which fails
# earlier and covers more.
# What is holding the address. Read this, not `instance_id`: an address serving
# a VPC's outbound path has no instance and no port, so it looks idle from every other
# angle. "unknown" means the platform did not say — never read it as "free".
output "partner_facing_attachment" {
value = frostmoln_public_ip.partner_facing.attachment.kind
}Schema
Optional
acknowledge_address_loss(Boolean) Set to true to allow this public IP to be released while it is serving a VPC's outbound traffic (attachment.kind= "gateway").
Releasing it loses the address permanently. It returns to a shared regional pool and is re-issued to whoever asks next, so a partner's allow-list entry or a DNS record naming it stops matching — and cannot be restored by re-creating anything.
The provider refuses that release without this flag, and refuses it BEFORE any request is sent, because the platform cannot refuse it for you on the path a correct configuration produces. When frostmoln_gateway.public_ip_id refers to this resource, Terraform destroys the gateway first; the platform then hands the address back as an ordinary unattached address, and the release that follows looks — to the platform — like the release of something idle.
Set it to true and apply, then destroy. Leaving it unset (the default) makes terraform destroy fail on this resource instead of silently giving the address away.
Remove it from the configuration again once the destroy is done, and do not leave it set on a steady-state resource. It is ordinary configuration, so a true left behind stays in state for the life of the resource and permanently disarms this control.
It is not a substitute for lifecycle { prevent_destroy = true }, which fails the plan rather than the apply and covers every reason an address can be destroyed, including ones this attribute does not gate.
instance_id(String) The ID of the instance to associate with. Set to associate, remove to disassociate.
~> frostmoln_public_ip.instance_id and the frostmoln_public_ip_association resource are mutually exclusive — never use both for the same address. Both express the SAME attachment, so both would manage it: whichever applies second undoes what the first did, every subsequent plan proposes the change again, and the configuration never converges. (It is the same conflict the AWS provider documents between aws_eip.instance and aws_eip_association.)
Pick one per address. Use frostmoln_public_ip.instance_id when the SAME configuration allocates the address, so the address and its attachment are created and destroyed together.
Use frostmoln_public_ip_association when the address ALREADY EXISTS (look it up with the frostmoln_public_ip data source), or when it has to outlive the instance it is attached to. Destroying that resource detaches the address and leaves it allocated to your tenant, whereas destroying a frostmoln_public_ip RELEASES the address for good.
~> Terraform cannot see that an ATTACHED address depends on the VPC's gateway. This resource attaches one when instance_id names an instance, and an address reaches the outside world only through a gateway — but nothing that attaches an address refers to frostmoln_gateway, so nothing orders the two. Terraform runs them concurrently and either can win.
On teardown the gateway can go first, and its delete is then refused ("Gateway is still in use", GATEWAY_IN_USE) because something in the VPC still depends on it — the failure that stops a terraform destroy half way through. On create the attachment can land first, and the platform then attaches a gateway ITSELF to carry it: a frostmoln_gateway that names a public_ip_id is refused after that ("VPC already has a gateway", GATEWAY_EXISTS), and one that names none is not refused at all — it quietly ADOPTS the gateway the platform made, leaving the VPC egressing from whatever address that gateway already had rather than one this configuration names, with origin reading implicit_public_ip.
Where the same configuration manages the gateway, state the ordering yourself: put depends_on = [frostmoln_gateway.<name>] on the resource that makes the ATTACHMENT — this one. Where the gateway is in another module, the dependency is on the module itself: depends_on = [module.<name>]. This resource is not the only one that needs it: frostmoln_apache_instance (public), frostmoln_kubernetes_cluster (public_ip_id), frostmoln_load_balancer (public_ip_id), frostmoln_nginx_instance (public) and frostmoln_public_ip_association attach addresses too, and each takes the line on itself.
It works only where the gateway is a frostmoln_gateway RESOURCE in the same configuration. A data "frostmoln_gateway" cannot carry the order — a data source is read, never created or destroyed — so depending on one defers a read and sequences nothing.
The ATTACHMENT is the place for it because an address that is merely allocated depends on nothing — and because an address resolved through the frostmoln_public_ip data source has no allocation resource to hang it on at all.
Never put it on an address that a frostmoln_gateway.public_ip_id names — the gateway already depends on that address, so a dependency back the other way is a plan-time Cycle: error, and that reference already sequences the two correctly without help.
Do not write it the other way about — on the gateway, listing what attaches. depends_on orders the resource it is written on, so that reverses both orders and turns a race that sometimes passed into a teardown that fails every time.
It changes ORDER only: nothing is created and nothing is released. It does not arm the gateway's own destroy either — without acknowledge_connectivity_loss the teardown stops at that refusal instead, and never reaches the ordering at all. And if a gateway was already adopted, nothing needs importing or rebuilding: it is in state already — add the ordering so it cannot recur, then give the gateway the address you meant with public_ip_id, which is applied in place.
tags(Map of String) Tags for the public IP.
Read-Only
address(String) The allocated IP address.attachment(Attributes) What is currently using this address. Never null — an address nothing is using reportskind = "none", soattachment.kindcan always be read.
Read this, not instance_id, to tell whether the address is free. An address serving a VPC's outbound traffic has no instance and no port, so a configuration that infers "unused" from an empty instance_id would offer to release the address a whole VPC leaves the platform from — and that release cannot be undone. (see below for nested schema)
created_at(String) The creation timestamp.id(String) The unique identifier of the public IP.private_ip(String) The private IP of the associated instance.status(String) The status of the public IP.
Nested Schema for attachment
Read-Only:
kind(String) "none" (allocated, nothing using it — still yours, still counted against quota and still billed), "port" (attached to an instance or load balancer, its inbound address), "gateway" (it is a VPC's outbound source address; seefrostmoln_gateway), or "unknown".
While it is "gateway" the platform refuses to attach this address to an instance, and this provider refuses to release it without acknowledge_address_loss = true.
"unknown" means the platform did not report an attachment for this address. Read it as "not established", never as "free": an address serving a VPC's outbound path has no port either, so nothing here distinguishes the two. New kinds can appear without a provider upgrade; a kind this provider build does not recognise is passed through unchanged and treated as attached.
resource_id(String) What holds the address: the network port for "port", the gateway for "gateway". Null for "none".vpc_id(String) The VPC whose outbound traffic leaves from this address. Set only for "gateway".