docs(design-proposals): add Terraform/OpenTofu backend for AGL#11
docs(design-proposals): add Terraform/OpenTofu backend for AGL#11Maxim Kitsunoff (kitsunoff) wants to merge 1 commit into
Conversation
Add a design proposal for extending Cozystack's Application Generation Layer to support Terraform/OpenTofu as a release backend alongside Helm, enabling AGL to manage cloud-side primitives (VPCs, DNS zones, managed services) under the same abstraction. Two alternative designs are documented for review: - Draft 1: a parallel TofuApplicationDefinition stack mirroring the existing Helm AGL one-to-one (minimal regression risk, high duplication). - Draft 2: a pluggable Backend interface behind a single ApplicationDefinition CRD (larger refactor, lower long-term cost). A short Marp slide deck summarising both drafts side-by-side is included. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: ZverGuy <maximbel2003@gmail.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces two design proposals for integrating OpenTofu/Terraform into Cozystack's Application Generation Layer (AGL). Draft 1 outlines a parallel stack approach, while Draft 2 proposes a refactored pluggable backend architecture to unify different deployment technologies. Feedback highlights several design considerations, including the need for per-tenant identity isolation in runner pods, maintaining a unified API group to hide implementation details, and establishing clear conventions for variable mapping and status projection to ensure a consistent developer experience across backends.
| runnerPodTemplate: # cloud creds, IRSA, custom image | ||
| spec: | ||
| serviceAccountName: tofu-runner |
There was a problem hiding this comment.
The runnerPodTemplate is defined at the cluster-scoped TofuApplicationDefinition level. In multi-tenant environments, different Application instances (e.g., belonging to different tenants) often require distinct cloud identities, such as different AWS IAM roles via IRSA. Hardcoding the serviceAccountName in the definition prevents per-tenant identity isolation. Consider allowing the Application spec to reference a local ServiceAccount or providing a mechanism to inject tenant-specific pod templates.
| ### API server changes | ||
|
|
||
| - New binary `cmd/cozystack-tofu-api/main.go` (or a feature-flagged subcommand) — boots an aggregation API server identical in shape to `cozystack-api`. | ||
| - Group: `tofu.apps.cozystack.io/v1alpha1` (separate to avoid kind collisions with Helm-side AGL). |
There was a problem hiding this comment.
Introducing a separate API group (tofu.apps.cozystack.io) for Terraform-backed resources exposes the implementation details to the end user. This fragmentation contradicts the goal of the Application Generation Layer, which is to provide a unified abstraction for infrastructure. Users should ideally interact with the same API group regardless of whether the backend is Helm, Terraform, or any other technology.
| Application.Name → Terraform.Name = prefix + Application.Name | ||
| Application.Namespace → Terraform.Namespace | ||
| Application.Labels → Terraform.Labels (with LabelPrefix) | ||
| Application.Spec (RawExtension) → Terraform.Spec.Vars (flattened, top-level keys = vars) |
There was a problem hiding this comment.
The proposal to flatten Application.Spec into Terraform.Spec.Vars needs a clearly defined strategy for handling nested objects. If the openAPISchema defines a hierarchical structure, a simple flattening might lead to key collisions or variable names that don't match the Terraform module's expectations. Explicitly documenting the flattening convention (e.g., using underscores for delimiters) or restricting Application.Spec to a flat map would avoid ambiguity.
| TofuAppDef.Terraform.RunnerPod… → Terraform.Spec.RunnerPodTemplate | ||
| ``` | ||
|
|
||
| `Application.Spec` keys become Terraform input variables. A small validator on the way in: keys must match `^[a-z_][a-z0-9_]*$` (HCL identifier). |
There was a problem hiding this comment.
The validator ^[a-z_][a-z0-9_]*$ enforces snake_case for input variables. Since Kubernetes properties typically use camelCase, this creates a naming convention conflict for package authors. Forcing users to use snake_case in their Application manifests to satisfy Terraform requirements breaks the Kubernetes-native feel of the AGL. An automatic translation layer (camelCase to snake_case) or an explicit mapping field would improve the developer experience.
| type Backend struct { | ||
| // +kubebuilder:validation:Enum=Helm;Terraform | ||
| Type BackendType `json:"type"` | ||
|
|
||
| Helm *HelmBackend `json:"helm,omitempty"` | ||
| Terraform *TerraformBackend `json:"terraform,omitempty"` | ||
| } |
There was a problem hiding this comment.
The Backend struct uses a discriminated union pattern but lacks validation to ensure that the field corresponding to the Type is actually populated. For example, if Type is set to Terraform, the Terraform field should be required. Adding +kubebuilder:validation rules or implementing a Validate method for the CRD would prevent invalid configurations from being persisted.
| Message string `json:"message,omitempty"` | ||
|
|
||
| // Backend-specific, raw JSON. Schema documented per backend. | ||
| Backend *runtime.RawExtension `json:"backend,omitempty"` |
There was a problem hiding this comment.
Using runtime.RawExtension for backend-specific status data makes it difficult for generic consumers (like the Cozystack dashboard or CLI) to provide a consistent user experience without being aware of every backend's internal structure. To maintain the "Generation Layer" abstraction, consider defining a structured Outputs map or a standard set of status fields that all backends must populate, using RawExtension only for truly opaque, backend-specific metadata.
Summary
Adds a design proposal for a Terraform/OpenTofu backend for Cozystack's Application Generation Layer (AGL).
Today AGL maps user-facing kinds (
Postgres,Kafka,Bucket, ...) to FluxHelmReleases. Helm is the only supported backend, which makes cloud-side primitives (VPCs, DNS zones, managed databases, IAM bindings, external buckets) awkward to express through the same abstraction. This proposal addsTerraformCRs of flux-iac/tofu-controller as a second backend, so platform engineers can describe cloud resources through AGL the same way they describe in-cluster workloads.Contents
design-proposals/agl-tofu-backends/:README.md— proposal overview, context, goals, non-goals, comparison of the two alternatives, recommendation, user-facing changes, upgrade/rollback, security, failure cases, testing, rollout, open questions.draft-1-parallel-tofu-stack.md— alternative 1: a newTofuApplicationDefinitionCRD with its own aggregation apiserver and reconciler, mirroring the existing Helm AGL one-to-one. Minimal regression risk, ~80% code duplication.draft-2-pluggable-backend.md— alternative 2: refactor AGL so Helm and Terraform are two implementations of oneBackendGo interface behind a singleApplicationDefinitionCRD. Larger refactor of the hot path, much lower long-term cost.presentation.md— Marp-flavoured slide deck summarising both drafts side-by-side.Status
Draft. The two drafts are alternatives, not sibling proposals — the intent is to decide between them (or commit to the hybrid recommendation: Draft 1 as PoC, then Draft 2 refactor) before implementation starts.
Open questions for reviewers
apps.cozystack.ioor use a distincttofu.apps.cozystack.io?approvePlanis manual — status field + dashboard, or a separateapprovesubresource onApplication?Reading these documents
Rendered, browsable version (with navigation and the Marp slide deck as HTML): https://kitsunoff.github.io/cozystack-agl-backends/.
Source repository: https://github.com/kitsunoff/cozystack-agl-backends.