Skip to content

Commit fdddfd0

Browse files
Merge pull request #13 from gitcommitankit/phase-3
feat(infra): add Terraform kind cluster and operator deployment module
2 parents 13b49f6 + 6242c7b commit fdddfd0

17 files changed

Lines changed: 622 additions & 17 deletions

File tree

.agents/skills/agentrax-context/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ description: Project context and settled architecture decisions for the Agentrax
2222
- **Traffic splitting**: Gateway API `HTTPRoute` weighted backends. Not Istio, not ingress annotations.
2323
- **Network Isolation**: Two-tier Kubernetes `NetworkPolicy` (`allow-metrics-traffic` in `agentrax-system` allowing operator metrics on TCP 8443; `tenant-agent-isolation` rendered into every `tenant-*` namespace selecting agent pods with `agentrax.io/agent: "true"` for scraping on TCP 8080 and egress to API server/CoreDNS in `kube-system`). No service mesh.
2424
- **Cloud Workload Identity**: No static cloud credentials ever. Azure deployments use AKS Workload Identity (`azure.workload.identity/client-id` + `/tenant-id` ServiceAccount annotations; `azure.workload.identity/use: "true"` pod label). AWS deployments use IRSA (`eks.amazonaws.com/role-arn` annotation). In Helm deployments, both are opt-in via `workloadIdentity.enabled` in `charts/agentrax/values.yaml` (disabled by default for portability); in Kustomize deployments, AWS IRSA is activated via the `config/workload-identity/irsa-serviceaccount.yaml` strategic-merge patch.
25+
- **Terraform IaC**: All cluster provisioning and Helm stack installation goes through the `infra/` Terraform modules (`kind_cluster` + `agentrax_stack`). Do not add raw shell provisioning scripts. Dev convenience via `make terraform-apply`; CI gate via `.github/workflows/terraform-lint.yml`.
2526
- **MCP registry**: embedded HTTP handler inside the operator process, backed by a `ConfigMap`. Not a separate Deployment, not a new database — HA storage is a v2 item.
2627
- **Non-goals**: no model training/fine-tuning, no general-purpose workload management, no service mesh, no UI in v1. Flag any drift toward these rather than quietly implementing them.
2728

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Terraform Lint
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "infra/**"
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
terraform-lint:
13+
name: fmt / tflint / trivy
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Terraform
21+
uses: hashicorp/setup-terraform@v3
22+
with:
23+
terraform_version: "1.9.5"
24+
25+
- name: Terraform Format Check
26+
run: terraform fmt -check -recursive infra/
27+
28+
- name: Set up TFLint
29+
uses: terraform-linters/setup-tflint@v4
30+
with:
31+
tflint_version: "v0.53.0"
32+
33+
- name: TFLint init
34+
run: tflint --init --config=infra/.tflint.hcl
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: TFLint
39+
run: tflint --chdir=infra/environments/dev --config="$(pwd)/infra/.tflint.hcl"
40+
41+
- name: Trivy IaC Scan
42+
uses: aquasecurity/trivy-action@v0.36.0
43+
with:
44+
scan-type: config
45+
scan-ref: infra/
46+
exit-code: "1"
47+
severity: HIGH,CRITICAL

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,16 @@ go.work
2828

2929
# Temporary design scratch pad
3030
rough/
31+
32+
# Terraform
33+
**/.terraform/
34+
*.tfstate
35+
*.tfstate.*
36+
crash.log
37+
crash.*.log
38+
override.tf
39+
override.tf.json
40+
*_override.tf
41+
*_override.tf.json
42+
infra/**/*-config
43+
*kubeconfig*

Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,26 @@ check-metrics: ## Diagnostic: check whether custom metrics are available via the
168168
$(KUBECTL) get --raw /apis/custom.metrics.k8s.io/v1beta1 2>/dev/null | python3 -m json.tool || \
169169
echo "Custom metrics API not available — ensure Prometheus Adapter is running."
170170

171+
##@ Terraform (Infrastructure)
172+
173+
TF_DIR ?= infra/environments/dev
174+
175+
.PHONY: terraform-init
176+
terraform-init: ## Initialise Terraform in the dev environment (downloads providers).
177+
terraform -chdir=$(TF_DIR) init
178+
179+
.PHONY: terraform-plan
180+
terraform-plan: ## Preview Terraform changes for the dev kind cluster.
181+
terraform -chdir=$(TF_DIR) plan
182+
183+
.PHONY: terraform-apply
184+
terraform-apply: ## Provision the dev kind cluster and deploy the full Agentrax stack. Set TF_AUTO_APPROVE=1 to skip confirmation prompt.
185+
terraform -chdir=$(TF_DIR) apply $(if $(TF_AUTO_APPROVE),-auto-approve)
186+
187+
.PHONY: terraform-destroy
188+
terraform-destroy: ## Tear down the dev kind cluster and all provisioned resources. Set TF_AUTO_APPROVE=1 to skip confirmation prompt.
189+
terraform -chdir=$(TF_DIR) destroy $(if $(TF_AUTO_APPROVE),-auto-approve)
190+
171191
##@ Dependencies
172192

173193
## Location to install dependencies to

docs/ARCHITECTURE.md

Lines changed: 73 additions & 17 deletions
Large diffs are not rendered by default.

infra/.tflint.hcl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# tflint configuration for the infra/ directory.
2+
# Enables the official Terraform plugin for provider-level schema validation.
3+
# Run: tflint --chdir=infra/environments/dev
4+
5+
plugin "terraform" {
6+
enabled = true
7+
preset = "recommended"
8+
}
9+
10+
# Enforce consistent code style.
11+
rule "terraform_naming_convention" {
12+
enabled = true
13+
}
14+
15+
rule "terraform_required_version" {
16+
enabled = true
17+
}
18+
19+
rule "terraform_required_providers" {
20+
enabled = true
21+
}
22+
23+
rule "terraform_documented_variables" {
24+
enabled = true
25+
}
26+
27+
rule "terraform_documented_outputs" {
28+
enabled = true
29+
}

infra/environments/dev/.terraform.lock.hcl

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infra/environments/dev/main.tf

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# dev environment — local kind cluster + agentrax stack
2+
# This is the primary target for local development, integration testing, and CI.
3+
# State is stored in a local backend file (terraform.tfstate) — not shared.
4+
5+
terraform {
6+
required_version = ">= 1.6"
7+
8+
# Local backend — intentional for dev. Do not check in terraform.tfstate.
9+
backend "local" {}
10+
11+
required_providers {
12+
kind = {
13+
source = "tehcyx/kind"
14+
version = "~> 0.6"
15+
}
16+
helm = {
17+
source = "hashicorp/helm"
18+
version = "~> 2.14"
19+
}
20+
kubernetes = {
21+
source = "hashicorp/kubernetes"
22+
version = "~> 2.31"
23+
}
24+
}
25+
}
26+
27+
# ---------------------------------------------------------------------------
28+
# Step 1: Provision the kind cluster
29+
# ---------------------------------------------------------------------------
30+
module "kind_cluster" {
31+
source = "../../modules/kind_cluster"
32+
cluster_name = var.cluster_name
33+
}
34+
35+
# ---------------------------------------------------------------------------
36+
# Step 2: Configure the Helm and Kubernetes providers to target the new cluster.
37+
# Both providers read credentials from the kind_cluster module outputs so no
38+
# local kubeconfig file needs to exist before `terraform apply`.
39+
# ---------------------------------------------------------------------------
40+
provider "helm" {
41+
kubernetes {
42+
host = module.kind_cluster.endpoint
43+
client_certificate = module.kind_cluster.client_certificate
44+
client_key = module.kind_cluster.client_key
45+
cluster_ca_certificate = module.kind_cluster.cluster_ca_certificate
46+
}
47+
}
48+
49+
provider "kubernetes" {
50+
host = module.kind_cluster.endpoint
51+
client_certificate = module.kind_cluster.client_certificate
52+
client_key = module.kind_cluster.client_key
53+
cluster_ca_certificate = module.kind_cluster.cluster_ca_certificate
54+
}
55+
56+
# ---------------------------------------------------------------------------
57+
# Step 3: Install cert-manager → kube-prometheus-stack → agentrax
58+
# ---------------------------------------------------------------------------
59+
module "agentrax_stack" {
60+
source = "../../modules/agentrax_stack"
61+
62+
cert_manager_version = var.cert_manager_version
63+
prometheus_stack_version = var.prometheus_stack_version
64+
agentrax_chart_path = var.agentrax_chart_path
65+
agentrax_leader_elect = var.agentrax_leader_elect
66+
agentrax_extra_values = var.agentrax_extra_values
67+
68+
# The stack module requires the cluster to exist first.
69+
# Provider-level dependency is enforced via the shared kubeconfig above.
70+
}

infra/environments/dev/outputs.tf

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# dev environment — outputs
2+
3+
output "cluster_endpoint" {
4+
description = "Kubernetes API server endpoint for the dev kind cluster."
5+
value = module.kind_cluster.endpoint
6+
}
7+
8+
output "agentrax_namespace" {
9+
description = "Namespace where the agentrax operator was deployed."
10+
value = module.agentrax_stack.agentrax_namespace
11+
}
12+
13+
output "agentrax_release_status" {
14+
description = "Helm release status for the agentrax chart."
15+
value = module.agentrax_stack.agentrax_release_status
16+
}
17+
18+
output "prometheus_namespace" {
19+
description = "Namespace where kube-prometheus-stack is deployed."
20+
value = module.agentrax_stack.prometheus_namespace
21+
}
22+
23+
output "kubeconfig" {
24+
description = "Raw kubeconfig for the kind cluster. Pipe into kubectl or save to a file."
25+
value = module.kind_cluster.kubeconfig
26+
sensitive = true
27+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# dev environment — variables
2+
3+
variable "cluster_name" {
4+
description = "Name of the local kind cluster."
5+
type = string
6+
default = "agentrax-dev"
7+
}
8+
9+
variable "cert_manager_version" {
10+
description = "cert-manager Helm chart version."
11+
type = string
12+
default = "v1.15.3"
13+
}
14+
15+
variable "prometheus_stack_version" {
16+
description = "kube-prometheus-stack Helm chart version."
17+
type = string
18+
default = "61.8.0"
19+
}
20+
21+
variable "agentrax_chart_path" {
22+
description = "Path to the agentrax Helm chart directory, relative to this environment root."
23+
type = string
24+
default = "../../../charts/agentrax"
25+
}
26+
27+
variable "agentrax_leader_elect" {
28+
description = "Enable leader election for the Agentrax controller manager."
29+
type = bool
30+
default = false
31+
}
32+
33+
variable "agentrax_extra_values" {
34+
description = "Additional Helm set key=value overrides for the agentrax release."
35+
type = map(string)
36+
default = {}
37+
}

0 commit comments

Comments
 (0)