Initial commit

This commit is contained in:
Scooby Husky
2026-03-09 20:21:35 -05:00
commit aacb8eebbe
314 changed files with 21766 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-n8n
namespace: n8n
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:16
instances: 2
# Resource limits to prevent OOM
resources:
requests:
memory: "512Mi"
cpu: "25m"
limits:
memory: "2Gi"
cpu: "250m"
# Spread replicas across different nodes
affinity:
topologyKey: kubernetes.io/hostname
storage:
size: 10Gi
storageClass: rook-ceph-block
primaryUpdateStrategy: unsupervised
# PostgreSQL configuration for better performance
postgresql:
parameters:
max_connections: "200"
shared_buffers: "512MB"
effective_cache_size: "1536MB"
maintenance_work_mem: "128MB"
checkpoint_completion_target: "0.9"
wal_buffers: "16MB"
default_statistics_target: "100"
random_page_cost: "1.1"
effective_io_concurrency: "200"
work_mem: "2621kB"
min_wal_size: "1GB"
max_wal_size: "4GB"
bootstrap:
initdb:
database: n8n
owner: n8n
monitoring:
enablePodMonitor: true
+40
View File
@@ -0,0 +1,40 @@
---
apiVersion: generators.external-secrets.io/v1alpha1
kind: Password
metadata:
name: n8n-cnpg-secret
namespace: n8n
spec:
length: 42
digits: 5
symbols: 5
symbolCharacters: "-_$@"
noUpper: false
allowRepeat: true
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: n8n-cnpg-secret
namespace: n8n
spec:
# Rotate database password every 24 hours
refreshInterval: "24h"
target:
# This will merge the generated password into the existing pg-n8n-app secret
name: pg-n8n-app
creationPolicy: Merge
template:
metadata:
labels:
cnpg.io/reload: "true"
data:
# Override the password field with our ESO-generated password
password: "{{ .password }}"
dataFrom:
- sourceRef:
generatorRef:
apiVersion: generators.external-secrets.io/v1alpha1
kind: Password
name: n8n-cnpg-secret
+20
View File
@@ -0,0 +1,20 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: n8n
namespace: n8n
spec:
parentRefs:
- name: edge
namespace: gateway
sectionName: https
hostnames:
- n8n.kube.huskypup.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: n8n
port: 80
+49
View File
@@ -0,0 +1,49 @@
# kubernetes/apps/n8n/external-secret.yaml
# ExternalSecrets for n8n - pulls credentials from Vault
# Note: Database password is managed by CNPG cluster (pg-n8n-app secret)
# We reference it directly in the n8n values.yaml extraEnv section
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: n8n-config
namespace: n8n
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: n8n-config-secret
creationPolicy: Owner
data:
- secretKey: encryption-key
remoteRef:
key: n8n-config
property: encryption-key
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: n8n-oauth
namespace: n8n
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: n8n-oauth-secret
creationPolicy: Owner
data:
- secretKey: client-id
remoteRef:
key: n8n-oauth
property: client-id
- secretKey: client-secret
remoteRef:
key: n8n-oauth
property: client-secret
+81
View File
@@ -0,0 +1,81 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: n8n-hooks
namespace: n8n
data:
hooks.js: |
// n8n v2.0.3 compatible hooks for Authentik forward auth integration
const { resolve, dirname } = require('path');
module.exports = {
credentials: {
create: [],
delete: [],
update: []
},
workflow: {
create: [],
delete: [],
update: []
},
server: {
started: [
async function (app) {
console.log('[n8n-hooks] Initializing forward auth middleware');
// Get Express app
const expressApp = app?.app;
if (!expressApp) {
console.error('[n8n-hooks] Express app not available');
return;
}
let issueCookie, UserRepository, Container;
try {
const n8nPath = dirname(require.resolve('n8n'));
issueCookie = require(resolve(n8nPath, 'dist/auth/jwt')).issueCookie;
UserRepository = require(resolve(n8nPath, 'dist/databases/repositories/user.repository')).UserRepository;
Container = require('typedi').Container;
} catch (error) {
console.error('[n8n-hooks] Failed to load dependencies:', error.message);
return;
}
const ignoreAuthRegexp = /^\/(assets|healthz|webhook|rest\/oauth2-credential|rest\/settings|static|icons|types)/;
// Add middleware for forward auth
expressApp.use(async (req, res, next) => {
try {
if (ignoreAuthRegexp.test(req.url)) return next();
if (req.cookies?.['n8n-auth']) return next();
if (!process.env.N8N_FORWARD_AUTH_HEADER) return next();
const headerName = process.env.N8N_FORWARD_AUTH_HEADER.toLowerCase().replace(/_/g, '-');
const email = req.headers[headerName];
if (!email) return next();
const userRepo = Container.get(UserRepository);
const user = await userRepo.findOne({ where: { email } });
if (!user) {
console.warn(`[n8n-hooks] User not found: ${email}`);
res.statusCode = 401;
res.end(`User ${email} not found. Please contact an admin.`);
return;
}
console.log(`[n8n-hooks] Auto-login: ${email}`);
issueCookie(res, user);
next();
} catch (error) {
console.error('[n8n-hooks] Middleware error:', error.message);
next();
}
});
console.log('[n8n-hooks] Forward auth middleware active');
}
]
}
};
@@ -0,0 +1,16 @@
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: n8n
namespace: n8n
spec:
hosts:
- n8n.kube.huskypup.net
gateways:
- istio-system/edge
http:
- route:
- destination:
host: n8n.n8n.svc.cluster.local
port:
number: 80