docs: update AGENTS.md to reflect Terraform->ArgoCD migration and ESO secrets flow
- Terraform now owns infra only (namespaces, Cloudflare, R2), not k8s config - Argo CD manages all k8s resources via git - Secrets: Vault -> ExternalSecret -> ESO -> k8s Secret (no Terraform secrets) - Updated Common Operations for new GitOps flow - Added tea CLI note, corrected repo paths
This commit is contained in:
@@ -58,14 +58,11 @@ export VAULT_ADDR=http://localhost:8200
|
|||||||
### How secrets flow to pods
|
### How secrets flow to pods
|
||||||
|
|
||||||
```
|
```
|
||||||
Vault → TF_VAR_* (via infrastructure.env) → kubernetes_secret (Terraform) → pod env via secretKeyRef
|
Vault (source of truth) → ExternalSecret (in git) → ESO operator → k8s Secret → pod env
|
||||||
```
|
```
|
||||||
|
|
||||||
Secrets in Terraform:
|
All k8s Secrets are managed by External Secrets Operator (ESO) pulling from Vault.
|
||||||
- `neuron-secrets` (neuron ns): GITHUB_WEBHOOK_SECRET, GITEA_WEBHOOK_SECRET, SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET
|
No secrets are stored in Terraform. Do not add `kubernetes_secret` resources to Terraform.
|
||||||
- `cloudflared-secret` (neuron ns): TUNNEL_TOKEN
|
|
||||||
- `github-runner-secret` (ci ns): ACCESS_TOKEN
|
|
||||||
- `gitea-db` (git ns): password
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,17 +72,28 @@ Secrets in Terraform:
|
|||||||
|
|
||||||
| Layer | Tool | What it owns |
|
| Layer | Tool | What it owns |
|
||||||
|-------|------|-------------|
|
|-------|------|-------------|
|
||||||
| Infrastructure | **Terraform** | Namespaces, PVCs, ConfigMaps, k8s Secrets, Ingresses, Helm releases |
|
| Infrastructure | **Terraform** | Namespaces, Cloudflare DNS/tunnels, R2 storage, Vault bootstrap |
|
||||||
| Applications | **Argo CD** | Deployments, Services |
|
| Configuration | **Argo CD** | All k8s resources: Deployments, Services, ConfigMaps, Ingresses, PVCs, ExternalSecrets, Helm releases |
|
||||||
|
| Secrets | **ESO → Vault** | All k8s Secrets — ExternalSecret manifests in git, values pulled from Vault at runtime |
|
||||||
|
|
||||||
**Never modify k8s resources directly with kubectl.** Always go through Terraform or Argo CD (Git push).
|
**Never modify k8s resources directly with kubectl.** Always go through Terraform or Argo CD (Git push).
|
||||||
|
|
||||||
|
**Secrets flow:**
|
||||||
|
```
|
||||||
|
Vault (source of truth) → ExternalSecret (in git) → ESO operator → k8s Secret → pod env
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding a new secret:
|
||||||
|
1. `vault kv put secret/<path> field=value`
|
||||||
|
2. Add ExternalSecret manifest to `k8s/<service>/` referencing that path
|
||||||
|
3. Push → Argo CD applies ExternalSecret → ESO syncs Secret within ~60s
|
||||||
|
|
||||||
### Running Terraform
|
### Running Terraform
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/Development/infrastructure/servers/servers/legion/
|
cd ~/Development/infrastructure/servers/legion/
|
||||||
direnv exec . terraform plan # load secrets + plan
|
terraform plan # uses direnv to load credentials
|
||||||
direnv exec . terraform apply # apply
|
terraform apply
|
||||||
```
|
```
|
||||||
|
|
||||||
State is stored in Cloudflare R2 bucket `legion-terraform-state`.
|
State is stored in Cloudflare R2 bucket `legion-terraform-state`.
|
||||||
@@ -95,20 +103,22 @@ State is stored in Cloudflare R2 bucket `legion-terraform-state`.
|
|||||||
Root app `legion-apps` watches `servers/legion/apps/` in the `will/infrastructure` Gitea repo.
|
Root app `legion-apps` watches `servers/legion/apps/` in the `will/infrastructure` Gitea repo.
|
||||||
Push to main → Argo CD syncs within ~30 seconds.
|
Push to main → Argo CD syncs within ~30 seconds.
|
||||||
|
|
||||||
App manifests: `~/Development/infrastructure/servers/servers/legion/apps/*.yaml`
|
- App manifests: `~/Development/infrastructure/servers/legion/apps/*.yaml`
|
||||||
|
- k8s config: `~/Development/infrastructure/servers/legion/k8s/<service>/*.yaml`
|
||||||
Argo CD UI: https://argocd.neuralplatform.ai
|
- Argo CD UI: https://argocd.neuralplatform.ai
|
||||||
|
- Gitea CLI: `tea pr ls`, `tea issue ls` (configured, default login: neuralplatform)
|
||||||
|
|
||||||
### Repo layout
|
### Repo layout
|
||||||
|
|
||||||
```
|
```
|
||||||
~/Development/
|
~/Development/
|
||||||
infrastructure/ ← this repo (local only, no GitHub remote)
|
infrastructure/ ← this repo (local only, no GitHub remote)
|
||||||
Agents.md ← you are here
|
AGENTS.md ← you are here
|
||||||
servers/ ← nested repo (will/infrastructure on Gitea)
|
servers/ ← nested repo (will/infrastructure on Gitea)
|
||||||
servers/legion/
|
legion/
|
||||||
*.tf ← Terraform (infrastructure layer)
|
*.tf ← Terraform (infra layer: namespaces, Cloudflare, R2)
|
||||||
apps/*.yaml ← Argo CD manifests (app layer)
|
apps/*.yaml ← Argo CD Application manifests (app definitions)
|
||||||
|
k8s/<service>/*.yaml ← k8s config synced by Argo CD (PVCs, ExternalSecrets, etc.)
|
||||||
neural-platform/
|
neural-platform/
|
||||||
neuron/ ← github: harmonic-framework/neuron, gitea: neural-platform/neuron
|
neuron/ ← github: harmonic-framework/neuron, gitea: neural-platform/neuron
|
||||||
harmonic-framework/
|
harmonic-framework/
|
||||||
@@ -237,28 +247,26 @@ Runner labels: `self-hosted,linux,x64,legion`
|
|||||||
|
|
||||||
### Deploy a config change to an app
|
### Deploy a config change to an app
|
||||||
|
|
||||||
1. Edit `servers/servers/legion/apps/<app>.yaml`
|
1. Edit `servers/legion/apps/<app>.yaml` or `servers/legion/k8s/<service>/<file>.yaml`
|
||||||
2. `git commit && git push` (from `servers/`)
|
2. `git commit && git push` (from `servers/`)
|
||||||
3. Argo CD syncs in ~30s
|
3. Argo CD syncs in ~30s
|
||||||
|
|
||||||
### Add a new secret to a pod
|
### Add a new secret to a pod
|
||||||
|
|
||||||
1. Add `kubernetes_secret` resource to the relevant `.tf` file (value from `var.X`)
|
1. Store the secret: `vault kv put secret/path field=value`
|
||||||
2. Add `variable "X"` to `variables.tf` (sensitive = true)
|
2. Add/update an ExternalSecret in `servers/legion/k8s/<service>/external-secrets.yaml`
|
||||||
3. Add `TF_VAR_X=$(_v path field)` to `infrastructure.env`
|
3. Reference `secretKeyRef: name: <secret-name>` in the app manifest
|
||||||
4. Store the secret: `vault kv put secret/path field=value`
|
4. Push → ESO syncs the k8s Secret within ~60s
|
||||||
5. `direnv exec . terraform apply`
|
|
||||||
6. Reference `secretKeyRef: name: <secret-name>` in the app manifest
|
|
||||||
|
|
||||||
### Add a new Helm service (stays in Terraform)
|
### Add a new Helm release
|
||||||
|
|
||||||
Add `helm_release` resource to appropriate `.tf` file, apply.
|
Add an Argo CD Application manifest to `servers/legion/apps/<name>.yaml` with `spec.source.chart` and `spec.source.helm.values`. Push to deploy.
|
||||||
|
|
||||||
### Rotate a secret
|
### Rotate a secret
|
||||||
|
|
||||||
1. Update value in Vault: `vault kv patch secret/path field=newvalue`
|
1. `vault kv patch secret/path field=newvalue`
|
||||||
2. Re-run `direnv exec . terraform apply` (updates kubernetes_secret)
|
2. Force ESO refresh: `kubectl annotate externalsecret -n <ns> <name> force-sync=$(date +%s) --overwrite`
|
||||||
3. Restart the affected pod: `kubectl rollout restart deployment/<name> -n <ns>`
|
3. Restart pod if needed: `kubectl rollout restart deployment/<name> -n <ns>`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -275,8 +283,10 @@ Add `helm_release` resource to appropriate `.tf` file, apply.
|
|||||||
|
|
||||||
## What NOT To Do
|
## What NOT To Do
|
||||||
|
|
||||||
- `kubectl apply` directly — use Terraform or push to Git
|
- `kubectl apply` directly — push to Git and let Argo CD sync
|
||||||
- `kubectl edit` — use Terraform or Git
|
- `kubectl edit` — edit the file in `servers/legion/`, push to Git
|
||||||
- Hardcode any secret value — always use `var.X` → Vault
|
- Hardcode any secret value — store in Vault, reference via ExternalSecret
|
||||||
|
- Add `kubernetes_secret` to Terraform — secrets belong in ESO/Vault, not Terraform
|
||||||
- Commit `terraform.tfstate` — state is in R2, never local
|
- Commit `terraform.tfstate` — state is in R2, never local
|
||||||
- Call Gitea API from Mac directly — CF Access blocks it, use SSH to Legion
|
- Call Gitea API from Mac directly — CF Access blocks it; use `tea` CLI or SSH to Legion
|
||||||
|
- Use `var.X` pattern for secrets in Terraform — Terraform no longer owns k8s Secrets
|
||||||
|
|||||||
Reference in New Issue
Block a user