feat: this estate's n8n deployment
The values that infra-n8n deliberately does not carry: our hostname, issuer, Vault path and images, plus the two things that are ours alone — the lab CA the workflows need to verify internal TLS, and the agents' Keycloak client secrets, read from the realm's own Vault entry so there is one source per secret. Self-managing after three applies, like the rest of the estate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
# The agents' Keycloak client secrets, for the workflows that act as those
|
||||||
|
# agents. Read from the realm's own Vault entry rather than copied into n8n's
|
||||||
|
# path: there is one source for a client secret, and rotating it in Vault
|
||||||
|
# rotates it everywhere instead of leaving a stale twin behind.
|
||||||
|
#
|
||||||
|
# A narrow grant — this names the properties it wants, so the namespace receives
|
||||||
|
# those and nothing else of the realm.
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: n8n-agent-secrets
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-keycloak
|
||||||
|
target:
|
||||||
|
name: n8n-agent-secrets
|
||||||
|
data:
|
||||||
|
- secretKey: APPROVISIONNEMENT_CLIENT_SECRET
|
||||||
|
remoteRef:
|
||||||
|
key: keycloak/classic-models-realm
|
||||||
|
property: KC_SECRET_CLASSIC_MODELS_AGENT_APPROVISIONNEMENT
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Watches ./deploy, so everything here — including itself — reconciles from git.
|
||||||
|
#
|
||||||
|
# Three manual applies, once. Nothing can watch ./deploy until the namespace and
|
||||||
|
# the source that serves it exist:
|
||||||
|
#
|
||||||
|
# kubectl apply -f deploy/namespace.yaml
|
||||||
|
# kubectl apply -f deploy/gitrepository-self.yaml
|
||||||
|
# kubectl apply -f deploy/bootstrap-kustomization.yaml
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: n8n-deploy-bootstrap
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
interval: 10m
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: agent-flows
|
||||||
|
path: ./deploy
|
||||||
|
prune: true
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# The lab CA, mounted into n8n as NODE_EXTRA_CA_CERTS so a workflow can call
|
||||||
|
# keycloak.sttlab.local and the domain gateways with TLS verified rather than
|
||||||
|
# disabled. A CA certificate is public by construction — this is the
|
||||||
|
# certificate, never the key.
|
||||||
|
#
|
||||||
|
# Issued by the sttlab-local-ca ClusterIssuer, valid until 2026-11-24.
|
||||||
|
# Regenerate on rotation:
|
||||||
|
# kubectl -n cert-manager get secret sttlab-local-ca \
|
||||||
|
# -o jsonpath='{.data.tls\.crt}' | base64 -d
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: sttlab-ca
|
||||||
|
namespace: n8n
|
||||||
|
data:
|
||||||
|
ca.crt: |
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDPDCCAiSgAwIBAgIUd/utDf+f0yQR3v3qTjZqx+wvTZMwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGTEXMBUGA1UEAwwOKi5zdHRsYWIubG9jYWwwHhcNMjUxMTI0MTUzODQ1WhcN
|
||||||
|
MjYxMTI0MTUzODQ1WjAZMRcwFQYDVQQDDA4qLnN0dGxhYi5sb2NhbDCCASIwDQYJ
|
||||||
|
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALj0sryq8qXtkShT/B+/EjVJNN/TLHIn
|
||||||
|
QJYc6xuUH/f7q3dYdLm4iH0XnFgrSQLUo4iqd/Mczef5iWCYwT5FFa7P17/TcLVf
|
||||||
|
gso0j41qNLBjGxDQGQ6Z1VCxi6oan8ow98rumjVj0E0Qgs5CX/rN+gcEmZ/TZFWU
|
||||||
|
qudVoztpeiVqJ0dxCIq+KMutzd1BU7BXx4VRO9Y+t1idUc7oY7BPmS2qPAN7TtXP
|
||||||
|
j1KhH2BgLsmF5GRhYHNS578eCltcmS2sbQ3c7GwOV96lpgF9TixEvFXeN4xk43E6
|
||||||
|
1COUD7CRiWAZ0XI8FMlpZGeNZeV4bbV/MqVig1ybWNOz9MDKYj3eoXUCAwEAAaN8
|
||||||
|
MHowHQYDVR0OBBYEFDbzYWOPr4vxa+VONs7xHbcNx70YMB8GA1UdIwQYMBaAFDbz
|
||||||
|
YWOPr4vxa+VONs7xHbcNx70YMA8GA1UdEwEB/wQFMAMBAf8wJwYDVR0RBCAwHoIO
|
||||||
|
Ki5zdHRsYWIubG9jYWyCDHN0dGxhYi5sb2NhbDANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||||
|
tU4p5/ONXm7x4YDzSeL8NdThVLguiFur0jcTxvvPUS4NFNsnQJk4OXxBgjy1YwpL
|
||||||
|
3i56/4mCEd9OCQF/Hl0eFwGZBzNKlMoTA08AC/lBDvPrnVjuUu0qe/b/2KOkhESa
|
||||||
|
x8rQNp0o8pcj0f29nu0JfRqYGkzy0Lh2qgXhPu2iC+t2PfdleRAky1tt68wogdFL
|
||||||
|
TvHDsJbVo/ihsPpONlSyHfxG6bb/0Mkz64PH46TTt9GvJflEKMqDwivNFUA1P5S/
|
||||||
|
U4Ic8Qapnxc7h2+WbRjmYrnuygC2wMBE6rL9OF3gwCr1fkgGGRr5lVRUq2X2HZV5
|
||||||
|
5jqViv6eurq8O61N3vWGCQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# This estate's n8n: the template from infra-n8n, with our values.
|
||||||
|
#
|
||||||
|
# Everything specific lives here rather than in that repo, so the same template
|
||||||
|
# deploys somebody else's n8n without carrying ours.
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: n8n
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
interval: 10m
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: infra-n8n
|
||||||
|
path: ./k8s
|
||||||
|
prune: true
|
||||||
|
wait: true
|
||||||
|
timeout: 5m
|
||||||
|
postBuild:
|
||||||
|
substitute:
|
||||||
|
NAMESPACE: n8n
|
||||||
|
N8N_HOSTNAME: n8n.sttlab.local
|
||||||
|
N8N_IMAGE: docker.n8n.io/n8nio/n8n:2.37.4
|
||||||
|
POSTGRES_IMAGE: postgres:16.10-alpine
|
||||||
|
N8N_STORAGE: 2Gi
|
||||||
|
POSTGRES_STORAGE: 5Gi
|
||||||
|
TIMEZONE: Europe/Paris
|
||||||
|
INGRESS_CLASS: nginx
|
||||||
|
INGRESS_BODY_SIZE: "50m"
|
||||||
|
TLS_ISSUER_NAME: sttlab-local-ca
|
||||||
|
TLS_ISSUER_KIND: ClusterIssuer
|
||||||
|
VAULT_SERVER: https://vault.sttlab.eu
|
||||||
|
VAULT_MOUNT: secrets
|
||||||
|
VAULT_SECRET_PATH: n8n/instance
|
||||||
|
VAULT_STORE_NAME: vault-n8n
|
||||||
|
VAULT_APPROLE_SECRET: vault-approle-n8n
|
||||||
|
# The agents' Keycloak client secrets, so a workflow can exchange tokens
|
||||||
|
# as the agent it represents. Created by agent-secrets.yaml beside this.
|
||||||
|
EXTRA_ENV_SECRET: n8n-agent-secrets
|
||||||
|
EXTRA_CA_CONFIGMAP: sttlab-ca
|
||||||
|
# "false" so a workflow can read $env.<AGENT>_CLIENT_SECRET. It means any
|
||||||
|
# workflow on this instance can read any variable in the pod — acceptable
|
||||||
|
# while it runs only this estate's agents, and not a moment longer.
|
||||||
|
BLOCK_ENV_ACCESS: "false"
|
||||||
|
EXECUTIONS_MAX_AGE_HOURS: "336"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# This repo, so ./deploy reconciles from git rather than from whoever last ran
|
||||||
|
# kubectl.
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
name: agent-flows
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
interval: 5m
|
||||||
|
url: https://gitea.sttlab.eu/stt/classic-models-agent-flows.git
|
||||||
|
ref:
|
||||||
|
branch: main
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# The generic n8n deployment template. It carries no value specific to this
|
||||||
|
# estate — every hostname, issuer and Vault path comes from the substitutions
|
||||||
|
# in flux-kustomization.yaml beside this file.
|
||||||
|
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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: n8n
|
||||||
Reference in New Issue
Block a user