# Bootstrapping Flux Operator with Terraform and OpenTofu for Kubernetes

DevFeed: [Bootstrapping Flux Operator with Terraform and OpenTofu for Kubernetes](<https://devfeed.tech/articles/blog-bootstrapping-flux-with-terraform-the-right-way-48650.md>)

Original publisher: [Read original article](<https://fluxcd.io/blog/2026/04/terraform-flux-operator-bootstrap/>)

Author: Matheus Pimenta

Published: 2026-04-28T09:00:00Z

Content type: tutorial

Language: en

Sources: [Flux - Blog](<https://devfeed.tech/sources/flux-blog.md>)

Topics: [Terraform](<https://devfeed.tech/topics/terraform.md>), [GitOps](<https://devfeed.tech/topics/gitops.md>), [Kubernetes](<https://devfeed.tech/topics/kubernetes.md>), [opentofu](<https://devfeed.tech/topics/opentofu.md>), [Helm charts](<https://devfeed.tech/topics/helm-charts.md>), [rbac](<https://devfeed.tech/topics/rbac.md>), [YAML](<https://devfeed.tech/topics/yaml.md>)

Tags: [gitops](<https://devfeed.tech/tags/gitops.md>), [helm](<https://devfeed.tech/tags/helm.md>), [kubernetes](<https://devfeed.tech/tags/kubernetes.md>), [opentofu](<https://devfeed.tech/tags/opentofu.md>), [rbac](<https://devfeed.tech/tags/rbac.md>), [repository](<https://devfeed.tech/tags/repository.md>), [staging](<https://devfeed.tech/tags/staging.md>), [terraform](<https://devfeed.tech/tags/terraform.md>), [yaml](<https://devfeed.tech/tags/yaml.md>)

## AI overview

This tutorial introduces a Terraform module compatible with OpenTofu that bootstraps Flux Operator in a Kubernetes cluster and then hands ongoing reconciliation to Flux. It describes ownership handoff, a shared GitOps repository, secret handling, and ordered prerequisites such as CNI components and Helm charts.

## Source excerpt

This post introduces a new Terraform module (fully compatible with OpenTofu) that bootstraps Flux Operator into a Kubernetes cluster and then steps aside, letting Flux do what Flux does best. Here are some of the problems it sets out to fix. Ownership handoff Terraform is the natural place to install Flux right after a cluster comes up, since credentials are in scope and providers are wired. But once Flux is online, every object Terraform applied is now also an object Flux wants to reconcile. The traditional workarounds (the fluxcd/flux provider, or chained helm_release resources) keep Terraform on the hook for steady-state reconciliation forever. This module takes a different approach. Terraform owns only the bootstrap mechanism: a namespace, temporary RBAC, and a Kubernetes Job that applies Flux Operator and the FluxInstance. The module implements a create-if-missing strategy. Flux adopts the resources and Terraform stops touching it. When inputs are unchanged, terraform plan shows zero diff. Using one GitOps repository The Terraform root module and the Flux manifests live side-by-side in the same repository, so the bootstrap inputs and the steady-state desired state are versioned together: repo/ ├── terraform/ # Terraform root module │ ├── main.tf │ ├── providers.tf │ └── variables.tf └── clusters/ └── staging/ # reconciled by Flux via FluxInstance.spec.sync.path └── flux-system/ ├── flux-instance.yaml # applied by the bootstrap Job ├── flux-operator-values.yaml # shared between Terraform and the Flux-managed HelmRelease ├── flux-operator.yaml # ResourceSet wrapping the Flux Operator HelmRelease ├── runtime-info.yaml # Git-managed fields of flux-runtime-info (optional) └── kustomization.yaml # configMapGenerator for flux-operator-values The Terraform module loads the same flux-instance.yaml that Flux will reconcile after bootstrap and provisions the Git pull secret it needs to keep syncing the repository: module "flux_operator_bootstrap" { source = "controlplanei