Skip to content

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 provider's selected tenant (tenant_id, else the credential's default), and its cluster_id must belong to that same tenant.

~> Upgrade note. Before provider v0.37.9 this resource ignored tenant_id and always acted on the credential's home tenant — a binding for a non-home cluster failed at apply rather than landing in the wrong place. A configuration that sets a non-home tenant_id and previously applied has its bindings in the HOME tenant: the first plan after upgrading reads a 404, drops them from state and proposes a create in the selected tenant. terraform state rm + re-import against the selected tenant, or point tenant_id at the home tenant.

Authoritative scope — who owns what on this resource, declared in internal/scopedecl and machine-checked against the schema.

Enacted and reconciled — every configurable attribute not listed below: the platform applies it, and a refresh reads the truth back.

Create-immutable — cluster_id, namespace, service_account: the binding is identified by its cluster, namespace and service account; changing one is a different binding.

Example Usage ​

terraform
# 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.
#
# 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 selected tenant (the provider's tenant_id).
  • 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 the frostmoln_api_key_scopes data source or fm 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 with frostmoln_iam_policy_attachment (directly, or through a group). Write null or omit the attribute for no scopes; an empty list is not a valid spelling.

    Notes on the policy-granted path:

  • 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 scopes is dropped, so verify after the drop, not after the attach.

  • Dropping scopes NARROWS 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 destroy tries the attachment first and fails. Destroy the binding with -target first — 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; the provider's tenant_id selects it).
  • 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:

shell
# Workload identity bindings are imported by their id.
terraform import frostmoln_workload_identity_binding.app <binding-id>