Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/agentrax-context/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ description: Project context and settled architecture decisions for the Agentrax
- **Traffic splitting**: Gateway API `HTTPRoute` weighted backends. Not Istio, not ingress annotations.
- **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.
- **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.
- **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`.
- **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.
- **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.

Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/terraform-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Terraform Lint

on:
pull_request:
paths:
- "infra/**"

permissions:
contents: read

jobs:
terraform-lint:
name: fmt / tflint / trivy
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.5"

- name: Terraform Format Check
run: terraform fmt -check -recursive infra/

- name: Set up TFLint
uses: terraform-linters/setup-tflint@v4
with:
tflint_version: "v0.53.0"

- name: TFLint init
run: tflint --init --config=infra/.tflint.hcl
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: TFLint
run: tflint --chdir=infra/environments/dev --config="$(pwd)/infra/.tflint.hcl"

- name: Trivy IaC Scan
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: config
scan-ref: infra/
exit-code: "1"
severity: HIGH,CRITICAL
Comment thread
coderabbitai[bot] marked this conversation as resolved.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ go.work

# Temporary design scratch pad
rough/

# Terraform
**/.terraform/
*.tfstate
*.tfstate.*
crash.log
crash.*.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json
infra/**/*-config
*kubeconfig*
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,26 @@ check-metrics: ## Diagnostic: check whether custom metrics are available via the
$(KUBECTL) get --raw /apis/custom.metrics.k8s.io/v1beta1 2>/dev/null | python3 -m json.tool || \
echo "Custom metrics API not available — ensure Prometheus Adapter is running."

##@ Terraform (Infrastructure)

TF_DIR ?= infra/environments/dev

.PHONY: terraform-init
terraform-init: ## Initialise Terraform in the dev environment (downloads providers).
terraform -chdir=$(TF_DIR) init

.PHONY: terraform-plan
terraform-plan: ## Preview Terraform changes for the dev kind cluster.
terraform -chdir=$(TF_DIR) plan

.PHONY: terraform-apply
terraform-apply: ## Provision the dev kind cluster and deploy the full Agentrax stack. Set TF_AUTO_APPROVE=1 to skip confirmation prompt.
terraform -chdir=$(TF_DIR) apply $(if $(TF_AUTO_APPROVE),-auto-approve)

.PHONY: terraform-destroy
terraform-destroy: ## Tear down the dev kind cluster and all provisioned resources. Set TF_AUTO_APPROVE=1 to skip confirmation prompt.
terraform -chdir=$(TF_DIR) destroy $(if $(TF_AUTO_APPROVE),-auto-approve)

##@ Dependencies

## Location to install dependencies to
Expand Down
90 changes: 73 additions & 17 deletions docs/ARCHITECTURE.md

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions infra/.tflint.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# tflint configuration for the infra/ directory.
# Enables the official Terraform plugin for provider-level schema validation.
# Run: tflint --chdir=infra/environments/dev

plugin "terraform" {
enabled = true
preset = "recommended"
}

# Enforce consistent code style.
rule "terraform_naming_convention" {
enabled = true
}

rule "terraform_required_version" {
enabled = true
}

rule "terraform_required_providers" {
enabled = true
}

rule "terraform_documented_variables" {
enabled = true
}

rule "terraform_documented_outputs" {
enabled = true
}
56 changes: 56 additions & 0 deletions infra/environments/dev/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions infra/environments/dev/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# dev environment — local kind cluster + agentrax stack
# This is the primary target for local development, integration testing, and CI.
# State is stored in a local backend file (terraform.tfstate) — not shared.

terraform {
required_version = ">= 1.6"

# Local backend — intentional for dev. Do not check in terraform.tfstate.
backend "local" {}

required_providers {
kind = {
source = "tehcyx/kind"
version = "~> 0.6"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.14"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.31"
}
}
}

# ---------------------------------------------------------------------------
# Step 1: Provision the kind cluster
# ---------------------------------------------------------------------------
module "kind_cluster" {
source = "../../modules/kind_cluster"
cluster_name = var.cluster_name
}

# ---------------------------------------------------------------------------
# Step 2: Configure the Helm and Kubernetes providers to target the new cluster.
# Both providers read credentials from the kind_cluster module outputs so no
# local kubeconfig file needs to exist before `terraform apply`.
# ---------------------------------------------------------------------------
provider "helm" {
kubernetes {
host = module.kind_cluster.endpoint
client_certificate = module.kind_cluster.client_certificate
client_key = module.kind_cluster.client_key
cluster_ca_certificate = module.kind_cluster.cluster_ca_certificate
}
}

provider "kubernetes" {
host = module.kind_cluster.endpoint
client_certificate = module.kind_cluster.client_certificate
client_key = module.kind_cluster.client_key
cluster_ca_certificate = module.kind_cluster.cluster_ca_certificate
}

# ---------------------------------------------------------------------------
# Step 3: Install cert-manager → kube-prometheus-stack → agentrax
# ---------------------------------------------------------------------------
module "agentrax_stack" {
source = "../../modules/agentrax_stack"

cert_manager_version = var.cert_manager_version
prometheus_stack_version = var.prometheus_stack_version
agentrax_chart_path = var.agentrax_chart_path
agentrax_leader_elect = var.agentrax_leader_elect
agentrax_extra_values = var.agentrax_extra_values

# The stack module requires the cluster to exist first.
# Provider-level dependency is enforced via the shared kubeconfig above.
}
27 changes: 27 additions & 0 deletions infra/environments/dev/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# dev environment — outputs

output "cluster_endpoint" {
description = "Kubernetes API server endpoint for the dev kind cluster."
value = module.kind_cluster.endpoint
}

output "agentrax_namespace" {
description = "Namespace where the agentrax operator was deployed."
value = module.agentrax_stack.agentrax_namespace
}

output "agentrax_release_status" {
description = "Helm release status for the agentrax chart."
value = module.agentrax_stack.agentrax_release_status
}

output "prometheus_namespace" {
description = "Namespace where kube-prometheus-stack is deployed."
value = module.agentrax_stack.prometheus_namespace
}

output "kubeconfig" {
description = "Raw kubeconfig for the kind cluster. Pipe into kubectl or save to a file."
value = module.kind_cluster.kubeconfig
sensitive = true
}
37 changes: 37 additions & 0 deletions infra/environments/dev/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# dev environment — variables

variable "cluster_name" {
description = "Name of the local kind cluster."
type = string
default = "agentrax-dev"
}

variable "cert_manager_version" {
description = "cert-manager Helm chart version."
type = string
default = "v1.15.3"
}

variable "prometheus_stack_version" {
description = "kube-prometheus-stack Helm chart version."
type = string
default = "61.8.0"
}

variable "agentrax_chart_path" {
description = "Path to the agentrax Helm chart directory, relative to this environment root."
type = string
default = "../../../charts/agentrax"
}

variable "agentrax_leader_elect" {
description = "Enable leader election for the Agentrax controller manager."
type = bool
default = false
}

variable "agentrax_extra_values" {
description = "Additional Helm set key=value overrides for the agentrax release."
type = map(string)
default = {}
}
22 changes: 22 additions & 0 deletions infra/environments/prod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Production Environment — Azure AKS (Stub)

This environment targets an Azure Kubernetes Service (AKS) cluster for production workloads. The `agentrax_stack` module is cloud-agnostic; the production configuration differs from `dev` in four ways:

1. **Remote State Backend**: State stored in Azure Blob Storage with state locking.
2. **Cloud Provider Authentication**: Uses `azurerm` / `azapi` providers authenticated via Azure OIDC / Workload Identity.
3. **High Availability**: `agentrax_leader_elect = true` with $\ge 2$ controller replicas.
4. **Workload Identity**: Cloud identity parameters passed via `agentrax_extra_values`.

## Activation Runbook (Future — Not Yet Implemented)

> [!NOTE]
> The `infra/environments/prod/` directory is a stub. No `main.tf` exists here yet. The steps below are guidance for when the production Terraform root module is implemented.

1. Provision the target AKS cluster and retrieve its kubeconfig credentials.
2. Configure `backend.tf` with the Azure Blob Storage container coordinates.
3. Export Azure authentication environment variables (`ARM_CLIENT_ID`, `ARM_TENANT_ID`, `ARM_SUBSCRIPTION_ID`, `ARM_USE_OIDC=true`).
4. Execute deployment:
```bash
terraform -chdir=infra/environments/prod init
terraform -chdir=infra/environments/prod apply
```
Loading
Loading