Summary
The flux-operator Helm release is managed by two systems at once. OpenTofu bootstraps it at a pinned version with no values; Flux then adopts the same release name/namespace and floats it from an OCIRepository with a much richer values set. Every tofu apply on eks/configure therefore fights Flux for ownership.
Evidence
Observed on mycluster-0, 2026-08-19:
$ helm list -n flux-system
NAME REVISION CHART APP VERSION
flux 1 flux-instance-0.55.0 v0.55.0
flux-operator 11 flux-operator-0.58.1+b93eb18c9dfb v0.58.1
$ kubectl get helmrelease -n flux-system
NAME READY STATUS
flux-operator True Helm upgrade succeeded for release flux-system/flux-operator.v11
with chart flux-operator@0.58.1+b93eb18c9dfb
The two owners:
| Owner |
Source |
Version |
Values |
| OpenTofu |
opentofu/eks/configure/main.tf → helm_release.flux_operator |
pinned var.flux_operator_version (0.55.0) |
none |
| Flux |
flux/operator/helmrelease.yaml + flux/sources/ocirepo-flux-operator.yaml |
floats on semver: ">=0.43.0 <1.0.0" → 0.58.1 |
web UI, Zitadel OIDC, networkPolicy.create: false |
tofu plan against live state:
~ resource "helm_release" "flux_operator" {
~ version = "0.58.1+b93eb18c9dfb" -> "0.55.0"
}
flux_instance is not affected — still revision 1, cleanly OpenTofu-owned.
Impact
Any terramate script run deploy (or any apply on eks/configure that is non-empty for another reason) downgrades the running operator to var.flux_operator_version and strips the Flux-managed values — the Flux web UI loses its OIDC config — until Flux reconciles it back, up to 10 minutes later (interval: 10m).
Low severity, self-healing, but surprising, and it makes eks/configure plans permanently non-empty, which hides real drift.
lifecycle.ignore_changes does NOT work
Worth recording, because it is the obvious first thing to reach for. Both variants make planning fail outright:
lifecycle {
ignore_changes = [version, values, set] # also tried: ignore_changes = all
}
Error: Error locating chart
with helm_release.flux_operator,
on main.tf line 127:
Unable to locate chart oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator:
failed to perform "FetchReference" on source:
ghcr.io/controlplaneio-fluxcd/charts/flux-operator:0.58.1_b93eb18c9dfb: not found
Ignoring version makes OpenTofu plan against the state value 0.58.1+b93eb18c9dfb. That +buildmeta suffix is what Flux writes when it resolves the OCI digest — it is not a published tag — and the Helm provider maps + → _ when looking one up. The 404 kills the plan before anything else runs.
Options considered
| Option |
Trade-off |
| Accept the flap |
Self-healing within 10m, but eks/configure plans stay permanently dirty |
Track var.flux_operator_version toward the floating version |
Shrinks the window; manual upkeep, always lagging |
tofu state rm helm_release.flux_operator after bootstrap |
OpenTofu stops tracking what Flux owns — but re-deploys then hit cannot re-use a name that is still in use again (the bug fixed in #1773) unless paired with upgrade_install = true, which reintroduces the version fight |
| Pin the OCIRepository to an exact version |
Kills the intentional auto-update on the operator |
No option is obviously correct — it is a design call about who owns the operator after bootstrap.
Context
Surfaced while fixing #1773 (the orphaned-failed-release wedge). Not caused by that PR; that PR's plan is simply the first non-empty one in a while, which is how this became visible.
Summary
The
flux-operatorHelm release is managed by two systems at once. OpenTofu bootstraps it at a pinned version with no values; Flux then adopts the same release name/namespace and floats it from an OCIRepository with a much richer values set. Everytofu applyoneks/configuretherefore fights Flux for ownership.Evidence
Observed on
mycluster-0, 2026-08-19:The two owners:
opentofu/eks/configure/main.tf→helm_release.flux_operatorvar.flux_operator_version(0.55.0)flux/operator/helmrelease.yaml+flux/sources/ocirepo-flux-operator.yamlsemver: ">=0.43.0 <1.0.0"→ 0.58.1networkPolicy.create: falsetofu planagainst live state:flux_instanceis not affected — still revision 1, cleanly OpenTofu-owned.Impact
Any
terramate script run deploy(or any apply oneks/configurethat is non-empty for another reason) downgrades the running operator tovar.flux_operator_versionand strips the Flux-managed values — the Flux web UI loses its OIDC config — until Flux reconciles it back, up to 10 minutes later (interval: 10m).Low severity, self-healing, but surprising, and it makes
eks/configureplans permanently non-empty, which hides real drift.lifecycle.ignore_changesdoes NOT workWorth recording, because it is the obvious first thing to reach for. Both variants make planning fail outright:
Ignoring
versionmakes OpenTofu plan against the state value0.58.1+b93eb18c9dfb. That+buildmetasuffix is what Flux writes when it resolves the OCI digest — it is not a published tag — and the Helm provider maps+→_when looking one up. The 404 kills the plan before anything else runs.Options considered
eks/configureplans stay permanently dirtyvar.flux_operator_versiontoward the floating versiontofu state rm helm_release.flux_operatorafter bootstrapcannot re-use a name that is still in useagain (the bug fixed in #1773) unless paired withupgrade_install = true, which reintroduces the version fightNo option is obviously correct — it is a design call about who owns the operator after bootstrap.
Context
Surfaced while fixing #1773 (the orphaned-failed-release wedge). Not caused by that PR; that PR's plan is simply the first non-empty one in a while, which is how this became visible.