# AGENTS.md ## Project Overview This is an **ArgoCD GitOps repository** that manages Kubernetes applications for the `au-syd1` cluster using a Kustomize + Helm pattern. Applications are deployed via ArgoCD ApplicationSets that watch directory patterns in this repo. The migration pattern for this repo is: **Terragrunt/Terraform → ArgoCD** (see `migration.md` for full guide). --- ## Essential Commands ```bash # Build and render manifests for a path (outputs to manifests//) make build apps/overlays/au-syd1/ make build clusters/au-syd1/bootstrap # Validate all apps and clusters with kubeconform make kubeconform # Clean generated manifests make clean # Quick build + inspect without persisting output kustomize build --enable-helm apps/overlays/au-syd1/ # Check all resource kinds produced by an overlay kustomize build --enable-helm apps/overlays/au-syd1/ | grep "^kind:" | sort | uniq -c # Run pre-commit checks against all files uvx pre-commit run --all-files ``` --- ## Directory Structure ``` argocd-apps/ ├── argocd/ │ ├── applicationsets/ # ArgoCD ApplicationSet definitions (platform.yaml, storage.yaml) │ └── projects/ # ArgoCD AppProject definitions (platform.yaml, storage.yaml) ├── apps/ │ ├── base/ # Base Kustomize resources per app (no cluster-specific config) │ │ └── / │ │ ├── kustomization.yaml │ │ ├── namespace.yaml │ │ ├── vaultauth.yaml # (if Vault-managed secrets) │ │ └── vaultstaticsecret.yaml │ └── overlays/ │ └── au-syd1/ # Cluster-specific overlays │ └── / │ ├── kustomization.yaml # references base + helmCharts │ └── values.yaml # Helm values for this cluster ├── clusters/ │ └── au-syd1/ │ ├── apps/ # Entry point: references apps/base (ArgoCD app-of-apps) │ └── bootstrap/ # ArgoCD install + initial Application manifest ├── ci/ │ ├── validate-apps.sh # kubeconform over apps/overlays/*/kustomization.yaml │ ├── validate-clusters.sh # kubeconform over clusters/*/kustomization.yaml │ └── validate-no-secrets.sh # pre-commit hook: blocks plain Kubernetes Secrets └── sources/ # Reference sources (Terraform configs, upstream charts, etc.) └── terraform-k8s/ # Original Terraform configs — reference when migrating ``` --- ## Adding a New Application Follow these 10 steps (detailed in `migration.md`): ### 1. Create base resources ``` apps/base// ├── kustomization.yaml ├── namespace.yaml ├── vaultauth.yaml # if needed └── vaultstaticsecret.yaml # if needed ``` ### 2. Create cluster overlay ``` apps/overlays/au-syd1// ├── kustomization.yaml └── values.yaml ``` **Overlay kustomization.yaml pattern:** ```yaml --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../../base/ helmCharts: - name: repo: version: "" releaseName: namespace: valuesFile: values.yaml ``` ### 3. Register in ApplicationSet Add a directory entry to `argocd/applicationsets/platform.yaml` (or `storage.yaml` for `csi-*` apps): ```yaml - path: apps/overlays/*/ ``` ### 4. Update AppProject In `argocd/projects/platform.yaml` (or `storage.yaml`): - Add the Helm repo URL to `sourceRepos` - Add the namespace to `destinations` - Add any required cluster-scoped resource types to `clusterResourceWhitelist` ### 5. Validate ```bash kustomize build --enable-helm apps/overlays/au-syd1/ make kubeconform ``` --- ## Secret Management **Plain Kubernetes `Secret` objects are blocked** by the pre-commit hook. Use Vault Operator CRDs instead: ### VaultAuth template ```yaml apiVersion: secrets.hashicorp.com/v1beta1 kind: VaultAuth metadata: name: default namespace: spec: method: kubernetes mount: k8s/au/syd1 vaultConnectionRef: vso-system/default allowedNamespaces: - kubernetes: role: serviceAccount: audiences: - vault tokenExpirationSeconds: 600 ``` ### VaultStaticSecret template ```yaml apiVersion: secrets.hashicorp.com/v1beta1 kind: VaultStaticSecret metadata: name: namespace: spec: vaultAuthRef: default mount: kv type: kv-v2 path: kubernetes/namespace//default/ refreshAfter: 5m destination: name: create: true overwrite: true hmacSecretData: true ``` --- ## YAML Conventions - **2-space indentation** (enforced by yamllint) - All files must end with a newline (`end-of-file-fixer`) - No trailing whitespace - YAML linting uses relaxed rules with `line-length: disable` (long base64/URLs are fine) - yamllint ignores `chart` directories (vendored Helm charts) - `---` document separator at top of every YAML file - Multiple documents in one file are allowed (e.g., `vaultstaticsecret.yaml` often contains multiple secrets) --- ## Kubernetes Labels Pattern Use standard `app.kubernetes.io/*` labels consistently: ```yaml labels: app.kubernetes.io/component: app.kubernetes.io/instance: app.kubernetes.io/name: app.kubernetes.io/version: ``` --- ## Resource Naming Conventions Files in `apps/base//` follow the pattern: ``` _.yaml ``` Examples: - `deployment_puppetserver-master.yaml` - `cronjob_g10k-code.yaml` - `configmap_puppetboard-config.yaml` - `horizontalpodautoscaler_puppetserver-compilers-autoscaler.yaml` - `service_puppet-headless.yaml` --- ## Helm Chart Vendoring Some overlays vendor Helm charts locally under `apps/overlays/au-syd1//charts//`. When a chart is vendored, the overlay's `kustomization.yaml` references the local path. When not vendored, it references the OCI or HTTP repo directly. Current Kubernetes target version: **1.33.7** (used by kubeconform in CI). --- ## Project Boundaries | Project | ApplicationSet | App pattern | |------------|---------------------------|--------------------------| | `platform` | `argocd/applicationsets/platform.yaml` | Named apps (cert-manager, puppet, woodpecker, etc.) | | `storage` | `argocd/applicationsets/storage.yaml` | `csi-*` apps | The `clusters/au-syd1/apps/` entry-point is deployed as a standalone ArgoCD `Application` (not an ApplicationSet) called `au-syd1-apps`. --- ## CI / Pre-commit Hooks Runs on every PR via Woodpecker CI (`.woodpecker/`): | Check | Tool | Trigger | |---|---|---| | YAML lint + general file checks | `pre-commit` (yamllint + pre-commit-hooks) | PR | | No plain Secrets | `ci/validate-no-secrets.sh` | PR (staged files) | | Kubernetes manifest validation | `kubeconform` via `make kubeconform` | PR | kubeconform skips: `CustomResourceDefinition`, `GpuDevicePlugin` (for apps validation). --- ## Git Workflow - Branch naming: `benvin/` (user prefix) - **Never `git add .`** — add only relevant files explicitly - If pre-commit modifies files, `git add -u` then `git commit --amend --no-edit` - Use `git push --force-with-lease` after amending --- ## Security Policies - `reloader.stakater.com/auto: "true"` annotation triggers rolling restarts on ConfigMap/Secret changes - Security contexts follow least-privilege: `drop: [all]` then add only required capabilities - `fsGroup: 999` on pod security context for Puppet workloads - `runAsUser: 0` is used only for init containers that need to set file permissions, then regular containers run as non-root