Architecting GitOps for Infrastructure: Declarative OpenTofu Provisioning with Flux
Architecting GitOps for Infrastructure: Declarative OpenTofu Provisioning with Flux
Introduction
The shift toward Platform Engineering requires infrastructure provisioning to be as declarative, observable, and automated as application deployments. Traditional Infrastructure-as-Code (IaC) workflows rely on external CI/CD pipelines running speculative plans. This model introduces challenges, including state drift, manual execution bottlenecks, and loosely managed cloud credentials.
By uniting OpenTofu—the open-source evolution of Terraform under the Linux Foundation—with Flux, enterprises can implement a true GitOps model for infrastructure. This approach eliminates configuration drift by continuously reconciling cloud resources against a Git-based source of truth, leveraging Kubernetes as the control plane.
Core Concepts & Architecture
A GitOps-driven infrastructure architecture uses the Kubernetes control plane to orchestrate, execute, and monitor OpenTofu modules. Rather than running execution runners on local machines or ephemeral CI agents, the reconciliation loop is handled by the Flux Tofu/Terraform Controller (tf-controller).
[ Git Repository ] │ (Pushes commits to infra definitions) ▼ [ Flux Source Controller ] │ (Syncs source files) ▼ [ Flux Tofu Controller ] ◄───► [ S3 Backend (State Storage) ] │ (Generates plan/apply) ▼ [ Cloud Provider API (AWS/GCP) ]
The architecture relies on three primary components:
-
Git Repository (Source of Truth): Contains modularized OpenTofu configuration files and variable definitions.
-
Flux Source Controller: Continuously polls the repository for changes and packages the directory as a tarball artifact.
-
Tofu Controller: Watches for artifact updates, instantiates ephemeral runner pods executing the designated OpenTofu binary version, synchronizes the state backend, and applies changes.
This continuous reconciliation loop runs an implicit tofu plan at designated intervals. If actual cloud resources diverge from Git, the controller flags a drift condition, allowing platform teams to automatically remediate or alert on out-of-band modifications.
Hands-on Implementation
To implement GitOps-driven cloud provisioning, we must deploy the Flux Tofu Controller and configure the target resource manifests.
Step 1: Define the GitRepository Source
Configure Flux to track the repository containing your OpenTofu definitions. Save this manifest as source-repository.yaml:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: opentofu-infra-source
namespace: flux-system
spec:
interval: 1m0s
url: https://github.com/enterprise/opentofu-infrastructure-aws
ref:
branch: main
Step 2: Configure the OpenTofu Custom Resource
Create the Terraform resource config (using the OpenTofu runner image) to execute the plan. Create tofu-provisioner.yaml:
apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
name: aws-network-fabric
namespace: flux-system
spec:
runnerPodTemplate:
spec:
image: ghcr.io/flux-iac/tf-runner:v0.15.0-tofu1.6.2
interval: 30m
approvePlan: auto
path: ./environments/production/vpc
sourceRef:
kind: GitRepository
name: opentofu-infra-source
namespace: flux-system
writeOutputsToSecret:
name: vpc-outputs-secret
outputs:
- vpc_id
- private_subnets
Applying these manifests prompts the controller to fetch the repository, launch a secure runner pod equipped with the OpenTofu v1.6.2 runtime, initialize state backends, and automatically apply the VPC network configuration.
Security & Best Practices
Adopting GitOps for infrastructure changes how cloud credentials and access patterns are secured:
-
Implement Principle of Least Privilege (PoLP): Avoid hardcoding static Cloud Provider API keys in Kubernetes secrets. Instead, configure IAM Roles for Service Accounts (IRSA) on AWS or Workload Identity on GCP. This binds your Kubernetes runner pod directly to temporary, cryptographically validated cloud credentials.
-
State File Encapsulation: Secure your remote state storage (e.g., AWS S3, HashiCorp Consul) with Server-Side Encryption (SSE) and strict IAM policies. Restrict state file access solely to the controller runner pods and designated platform engineering roles.
-
Strict Plan Approval Workflows: For critical environments like production, switch
approvePlantomanual. The controller will generate the execution plan, export it to a Kubernetes secret, and pause execution until an authorized engineer runs a patch command or updates a pull request status:
kubectl -n flux-system patch terraform aws-network-fabric \
--type=merge -p '{"spec":{"approvePlan":"plan-xxxx"}}'
Conclusion
Decoupling infrastructure provisioning from legacy CI/CD pipelines and hosting it inside a Kubernetes-native GitOps pipeline transforms platform scalability. By executing OpenTofu via Flux, enterprises establish a secure, auditable, and self-healing control loop. This architectural pattern reduces configuration drift, enforces rigorous security boundaries through cloud workload identity, and ensures that the infrastructure state remains consistently aligned with the declarative source of truth.
