frostmoln_workload_identity_binding (Resource)
Manages a Workload Identity Federation binding, mapping a managed Kubernetes (namespace, service account) to a least-privilege Frostmoln grant. A pod running as that service account can exchange its projected token for a short-lived, scoped Frostmoln credential. The grant is either flat scopes or an access policy attached with frostmoln_iam_policy_attachment — a policy expresses far narrower least privilege (per-resource targets, constraints, explicit denies), so prefer it for new bindings. The binding is owned by the tenant resolved from the provider credential (API key or OIDC session), not by a provider tenant_id override.
Example Usage
# A Workload Identity Federation binding: a pod running as the given
# Kubernetes service account can exchange its projected token for a short-lived,
# scoped Frostmoln credential — no long-lived secret in the pod.
resource "frostmoln_workload_identity_binding" "app" {
cluster_id = frostmoln_kubernetes_cluster.prod.id
namespace = "default"
service_account = "my-app"
# Least-privilege scopes only. Wildcards ("*" or "<resource>:*") are rejected.
scopes = [
"compute:read",
"storage:read",
]
}
# A POLICY-GRANTED binding: omit `scopes` entirely and let an attached access
# policy be the workload's sole authority. Prefer this — a flat scope grants a
# verb across every resource of a service, while a policy names individual
# targets, adds constraints and can deny explicitly. Needs the `iam-policies`
# entitlement.
#
# The binding is INERT until the attachment exists: with no grant at all the
# token exchange refuses it rather than minting a credential that grants nothing.
#
# TEARDOWN — read before you destroy. A granted binding is never left with zero
# grants, so detaching its ONLY policy is refused. `terraform destroy` removes
# the attachment first (it depends on the binding) and therefore fails. Destroy
# the BINDING first; that removes its attachments with it:
#
# terraform destroy -target=frostmoln_workload_identity_binding.reaper
# terraform destroy
#
# The same applies to any change that REPLACES the binding (cluster_id, namespace
# and service_account all force replacement).
resource "frostmoln_workload_identity_binding" "reaper" {
cluster_id = frostmoln_kubernetes_cluster.prod.id
namespace = "ops"
service_account = "instance-reaper"
}
data "frostmoln_iam_policy_document" "reaper" {
rule {
name = "read-and-delete-instances-only"
access = "allow"
operations = ["compute:instances:read", "compute:instances:list", "compute:instances:delete"]
targets = ["frn:compute:*:*:instances/*"]
}
}
resource "frostmoln_iam_policy" "reaper" {
name = "instance-reaper"
document = data.frostmoln_iam_policy_document.reaper.json
}
resource "frostmoln_iam_policy_attachment" "reaper" {
policy_id = frostmoln_iam_policy.reaper.id
attachee_type = "workload_identity"
attachee_id = frostmoln_workload_identity_binding.reaper.id
}Schema
Required
cluster_id(String) The managed cluster the binding applies to. The cluster must belong to the caller's tenant.namespace(String) The Kubernetes namespace (DNS-1123 label).service_account(String) The Kubernetes service account name (DNS-1123 subdomain).
Optional
scopes(List of String) The least-privilege scopes granted to the workload (e.g.compute:read). The grantable set, with a description of each, is served by the platform — read it with thefrostmoln_api_key_scopesdata source orfm account api-key scopes. Wildcards (*or<resource>:*) are rejected. Changing the scopes updates the binding in place. Optional: omit it to author a policy-granted binding, whose authority comes entirely from an access policy attached withfrostmoln_iam_policy_attachment(directly, or through a group). Writenullor omit the attribute for no scopes; an empty list is not a valid spelling.
Notes on the policy-granted path:
- The policy-granted path needs the
iam-policiesentitlement. Without it the binding is still created, butfrostmoln_iam_policyfails and the binding is left inert. - Until a policy is attached the binding is inert — the token exchange refuses it rather than minting a credential that grants nothing.
- While a binding carries BOTH scopes and a policy, its scopes stay authoritative and the policy's additional authority does not take effect. It goes live only once
scopesis dropped, so verify after the drop, not after the attach. - Dropping
scopesNARROWS the workload to whatever the policy allows, and the API only checks that some grant survives — never that the policy covers what the scopes covered. Enumerate the binding's effective access before dropping them. - Removing the LAST grant is rejected outright. A binding whose only grant is an attached policy must therefore be destroyed BEFORE that attachment; a plain
terraform destroytries the attachment first and fails. Destroy the binding with-targetfirst — that removes its attachments with it.
Read-Only
created_at(String) The timestamp when the binding was created.id(String) The unique identifier of the binding.tenant_id(String) The owning tenant (server-set from the auth context).updated_at(String) The timestamp when the binding was last updated.
Import
Import is supported using the following syntax:
The terraform import command can be used, for example:
# Workload identity bindings are imported by their id.
terraform import frostmoln_workload_identity_binding.app <binding-id>