feat: deploy n8n on the cluster

The runtime for the estate's autonomous agents. Postgres as a StatefulSet with
its own claim, n8n behind a cert-manager certificate and the nginx ingress, and
both secrets in Vault behind an AppRole scoped to n8n/* alone.

The certificate is issued into the cluster rather than copied into the repo, so
the private key never reaches git. The CA certificate is committed and mounted
as NODE_EXTRA_CA_CERTS, so a workflow can reach keycloak and the domain
gateways without anyone disabling verification to make it work.

One replica and strategy: Recreate, both deliberate — n8n needs Redis and queue
mode before a second scheduler is safe, and a ReadWriteOnce volume deadlocks a
rolling update.

N8N_ENCRYPTION_KEY is generated once and kept in Vault. Regenerating it does not
re-encrypt the stored credentials, it orphans them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Stéphane Tailland
2026-08-29 12:34:40 +02:00
commit dc13738e86
17 changed files with 552 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
# Watches ./dev, so the GitRepository and the Kustomization below it reconcile
# from git like any other manifest. It lives in ./dev itself, so it also manages
# itself — the arrangement `flux bootstrap` sets up, which flux-operator does not
# create, and the same one the rest of the estate uses.
#
# Three manual applies, once, to close the loop — nothing can watch ./dev until
# the namespace and the source that serves it exist:
#
# kubectl apply -f k8s/namespace.yaml
# kubectl apply -f dev/gitrepository.yaml
# kubectl apply -f dev/bootstrap-kustomization.yaml
#
# After that every file in this repo, this one included, reconciles from git.
#
# Sharp edge: with prune enabled, deleting flux-kustomization.yaml from git
# deletes the Kustomization it defines, and that Kustomization's own prune then
# removes the deployment — including, on the PVCs, the workflows. The
# volumeClaimTemplate on Postgres survives that; n8n-data does not.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-n8n-bootstrap
namespace: n8n
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: infra-n8n
path: ./dev
prune: true
+14
View File
@@ -0,0 +1,14 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-n8n
namespace: n8n
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: infra-n8n
path: ./k8s
prune: true
wait: true
timeout: 5m
+14
View File
@@ -0,0 +1,14 @@
# HTTPS with no credentials: the repo is anonymously readable over HTTPS on
# gitea, so a deploy key would guard nothing while adding a Vault entry and a
# gitea key to create by hand before anything deploys. TLS still gives integrity
# and authenticity of the source.
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: infra-n8n
namespace: n8n
spec:
interval: 5m
url: https://gitea.sttlab.eu/stt/infra-n8n.git
ref:
branch: main