diff --git a/projects/maison/architecture.d2 b/projects/maison/architecture.d2
index 4eacfc87..2b23b9ba 100644
--- a/projects/maison/architecture.d2
+++ b/projects/maison/architecture.d2
@@ -280,17 +280,16 @@ maison: {
# - n8n
n8n: {
- class: [application; undeployed]
+ class: [application]
icon: assets/icons/apps/n8n.svg
link: https://n8n.io/
tooltip: Secure and AI-native workflow automation tool for technical people.
}
n8n <- _.system.Traefik: {
- class: [undeployed]
source-arrowhead: HTTP (5678)
}
n8n <- _.system.Tailscale: {
- class: [connect-vpn; undeployed]
+ class: [connect-vpn]
source-arrowhead: HTTP (5678)
}
diff --git a/projects/maison/assets/architecture.svg b/projects/maison/assets/architecture.svg
index 23d5420a..01b05360 100644
--- a/projects/maison/assets/architecture.svg
+++ b/projects/maison/assets/architecture.svg
@@ -1,13 +1,13 @@
-
-INTERNETLOCALNET☸ kubernetes.maison.chezmoi.shsystemmultimedialife-managementautomationothersCert-ManagerCert-Manager is a Kubernetes controller that automates the management and issuance of TLS certificates.ExternalDNSExternalDNS is a Kubernetes controller that configures DNS resources.TailscaleTailScale is a mesh VPN that makes it easy to connect your devices, wherever they are.FluxCDOpen and extensible continuous delivery solution for KubernetesTraefikTraefik is a modern HTTP reverse proxy and load balancer.External-SecretExternal-Secret is a Kubernetes controller that allows you to use external secret management systems.CloudNativePGCloudNativePG is a comprehensive platform designed to seamlessly manage PostgreSQL databases within Kubernetes environments.FileflowsFileFlows is a file processing application that can execute actions against a file in a tree flow structure.JellyfinJellyfin is the volunteer-built media solution that puts you in control of your media.JellyseerrFree and open source software application for managing requests for Jellyfin libraries.Actual-BudgetActual Budget is a personal finance app that helps you track your spending and save money.MealieIntuitive and easy to use recipe management app.DocspellDocspell is a personal document management system.n8nSecure and AI-native workflow automation tool for technical people.BudibaseA modern, open source low-code platform for building modern internal applications in minutes.LinkdingLinkding is a self-hosted bookmarking and link aggregation service. HTTPS (443) HTTPS (443) VPN HTTPS (443) HTTP (80)HTTPS (443) HTTP (19200) HTTP (19200) HTTP (8096) HTTP (8096) HTTP (8096) HTTP (5055) HTTP (5055) HTTP (5006) HTTP (5006) HTTP (9000) HTTP (9000) HTTP (7880) HTTP (7880) HTTP (5678) HTTP (5678) HTTP (8080) HTTP (8080) HTTP (9090) HTTP (9090)Cert-Manager is a Kubernetes controller that automates the management and issuance of TLS certificates.
+INTERNETLOCALNET☸ kubernetes.maison.chezmoi.shsystemmultimedialife-managementautomationothersCert-ManagerCert-Manager is a Kubernetes controller that automates the management and issuance of TLS certificates.ExternalDNSExternalDNS is a Kubernetes controller that configures DNS resources.TailscaleTailScale is a mesh VPN that makes it easy to connect your devices, wherever they are.FluxCDOpen and extensible continuous delivery solution for KubernetesTraefikTraefik is a modern HTTP reverse proxy and load balancer.External-SecretExternal-Secret is a Kubernetes controller that allows you to use external secret management systems.CloudNativePGCloudNativePG is a comprehensive platform designed to seamlessly manage PostgreSQL databases within Kubernetes environments.FileflowsFileFlows is a file processing application that can execute actions against a file in a tree flow structure.JellyfinJellyfin is the volunteer-built media solution that puts you in control of your media.JellyseerrFree and open source software application for managing requests for Jellyfin libraries.Actual-BudgetActual Budget is a personal finance app that helps you track your spending and save money.MealieIntuitive and easy to use recipe management app.DocspellDocspell is a personal document management system.n8nSecure and AI-native workflow automation tool for technical people.BudibaseA modern, open source low-code platform for building modern internal applications in minutes.LinkdingLinkding is a self-hosted bookmarking and link aggregation service. HTTPS (443) HTTPS (443) VPN HTTPS (443) HTTP (80)HTTPS (443) HTTP (19200) HTTP (19200) HTTP (8096) HTTP (8096) HTTP (8096) HTTP (5055) HTTP (5055) HTTP (5006) HTTP (5006) HTTP (9000) HTTP (9000) HTTP (7880) HTTP (7880) HTTP (5678) HTTP (5678) HTTP (8080) HTTP (8080) HTTP (9090) HTTP (9090)Cert-Manager is a Kubernetes controller that automates the management and issuance of TLS certificates.
@@ -1323,7 +1323,7 @@ interact with each other.
-
+
diff --git a/projects/maison/src/apps/kustomization.yaml b/projects/maison/src/apps/kustomization.yaml
index af7be8a8..cb5ae7d9 100644
--- a/projects/maison/src/apps/kustomization.yaml
+++ b/projects/maison/src/apps/kustomization.yaml
@@ -10,3 +10,4 @@ resources:
- jellyseerr.yaml
- linkding.yaml
- mealie.yaml
+ - n8n.yaml
diff --git a/projects/maison/src/apps/n8n.yaml b/projects/maison/src/apps/n8n.yaml
new file mode 100644
index 00000000..8b0c7467
--- /dev/null
+++ b/projects/maison/src/apps/n8n.yaml
@@ -0,0 +1,18 @@
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+ name: n8n
+spec:
+ interval: 12h0m0s
+ timeout: 30s
+ retryInterval: 0s
+
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
+ namespace: flux-system
+ path: ./projects/maison/src/apps/n8n
+
+ prune: true
+ wait: true
diff --git a/projects/maison/src/apps/n8n/n8n.database.yaml b/projects/maison/src/apps/n8n/n8n.database.yaml
new file mode 100644
index 00000000..3a941283
--- /dev/null
+++ b/projects/maison/src/apps/n8n/n8n.database.yaml
@@ -0,0 +1,21 @@
+---
+apiVersion: postgresql.cnpg.io/v1
+kind: Cluster
+metadata:
+ name: n8n
+ namespace: n8n
+ labels:
+ app.kubernetes.io/component: database
+ app.kubernetes.io/instance: n8n-database
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/part-of: n8n
+spec:
+ bootstrap:
+ initdb:
+ database: n8n
+ owner: n8n
+ description: PostgreSQL database dedicated to n8n
+ instances: 1
+
+ storage:
+ size: 5Gi
diff --git a/projects/maison/src/apps/n8n/n8n.deployment.yaml b/projects/maison/src/apps/n8n/n8n.deployment.yaml
new file mode 100644
index 00000000..56b485f1
--- /dev/null
+++ b/projects/maison/src/apps/n8n/n8n.deployment.yaml
@@ -0,0 +1,247 @@
+---
+# trunk-ignore(checkov/CKV_K8S_11): DO NOT SET the CPU limit
+# trunk-ignore(checkov/CKV_K8S_15,checkov/CKV_K8S_43): Not aggreed with theses policies about the ImagePullPolicy=Always and digest verification.
+# trunk-ignore(checkov/CKV2_K8S_6)
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: n8n
+ namespace: n8n
+ labels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ app.kubernetes.io/part-of: n8n
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ spec:
+ automountServiceAccountToken: false
+ containers:
+ # trunk-ignore(trivy/KSV011): DO NOT SET the CPU limit
+ - name: n8n
+ env:
+ - name: DB_POSTGRESDB_DATABASE_FILE
+ value: /run/secrets/n8n/postgres/dbname
+ - name: DB_POSTGRESDB_HOST_FILE
+ value: /run/secrets/n8n/postgres/host
+ - name: DB_POSTGRESDB_PASSWORD_FILE
+ value: /run/secrets/n8n/postgres/password
+ - name: DB_POSTGRESDB_PORT_FILE
+ value: /run/secrets/n8n/postgres/port
+ - name: DB_POSTGRESDB_USER_FILE
+ value: /run/secrets/n8n/postgres/user
+ - name: DB_TYPE
+ value: postgresdb
+ - name: N8N_DIAGNOSTICS_ENABLED
+ value: "false"
+ - name: N8N_EDITOR_BASE_URL
+ value: https://n8n.chezmoi.sh
+ - name: N8N_EMAIL_MODE
+ value: smtp
+ - name: N8N_HIDE_USAGE_PAGE
+ value: "true"
+ - name: N8N_HIRING_BANNER_ENABLED
+ value: "false"
+ - name: N8N_HOST
+ value: n8n.chezmoi.sh
+ - name: N8N_LISTEN_ADDRESS
+ value: 0.0.0.0
+ - name: N8N_PORT
+ value: "5678"
+ - name: N8N_PROTOCOL
+ value: http
+ - name: N8N_SMTP_HOST_FILE
+ value: /run/secrets/n8n/smtp/aws_ses_host
+ - name: N8N_SMTP_PASS_FILE
+ value: /run/secrets/n8n/smtp/aws_ses_password
+ - name: N8N_SMTP_PORT_FILE
+ value: /run/secrets/n8n/smtp/aws_ses_port
+ - name: N8N_SMTP_SENDER_FILE
+ value: /run/secrets/n8n/smtp/aws_ses_sender
+ - name: N8N_SMTP_USER_FILE
+ value: /run/secrets/n8n/smtp/aws_ses_username
+ - name: N8N_TEMPLATES_ENABLED
+ value: "true"
+ - name: N8N_USER_FOLDER
+ value: /opt/n8n/data
+ - name: TZ
+ value: Europe/Paris
+ - name: VUE_APP_URL_BASE_API
+ value: https://n8n.chezmoi.sh
+ image: docker.n8n.io/n8nio/n8n:1.72.1
+ livenessProbe:
+ httpGet:
+ path: /
+ port: http
+ ports:
+ - name: http
+ containerPort: 5678
+ protocol: TCP
+ readinessProbe:
+ httpGet:
+ path: /
+ port: http
+ resources:
+ requests:
+ cpu: 100m
+ memory: 1Gi
+ limits:
+ memory: 1Gi
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 16727
+ runAsGroup: 16727
+ seccompProfile:
+ type: RuntimeDefault
+ volumeMounts:
+ - name: cnpg-config
+ mountPath: /run/secrets/n8n/postgress
+ readOnly: true
+ - name: smtp-config
+ mountPath: /run/secrets/n8n/smtp
+ readOnly: true
+ - name: n8n-persistent
+ mountPath: /opt/n8n
+ - name: n8n-cache
+ mountPath: /opt/n8n/.cache
+ securityContext:
+ runAsNonRoot: true
+ runAsUser: 16727
+ runAsGroup: 16727
+ fsGroup: 16727
+ volumes:
+ - name: cnpg-config
+ secret:
+ secretName: n8n-app
+ - name: smtp-config
+ secret:
+ secretName: n8n-smtp-credentials
+ - name: n8n-persistent
+ persistentVolumeClaim:
+ claimName: n8n-persistent
+ - name: n8n-cache
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: n8n
+ namespace: n8n
+ labels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ app.kubernetes.io/part-of: n8n
+spec:
+ selector:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ ports:
+ - name: http
+ port: 80
+ targetPort: http
+ protocol: TCP
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: n8n-persistent
+ namespace: n8n
+ labels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ app.kubernetes.io/part-of: n8n
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+ labels:
+ app.kubernetes.io/name: n8n
+ app.kubernetes.io/instance: n8n
+ app.kubernetes.io/part-of: n8n
+ name: n8n-smtp
+ namespace: n8n
+spec:
+ data:
+ - remoteRef:
+ key: apps-n8n-aws-ses
+ property: username
+ secretKey: aws-ses-username
+ - remoteRef:
+ key: apps-n8n-aws-ses
+ property: password
+ secretKey: aws-ses-password
+ secretStoreRef:
+ kind: ClusterSecretStore
+ name: kubernetes.maison.chezmoi.sh
+ target:
+ name: n8n-smtp-credentials
+ template:
+ type: Opaque
+ engineVersion: v2
+ data:
+ aws_ses_host: email-smtp.us-east-1.amazonaws.com
+ aws_ses_username: "{{ .aws-ses-username }}"
+ aws_ses_password: "{{ .aws-ses-password }}"
+ aws_ses_port: "587"
+ aws_ses_sender: n8n
+# ---
+# apiVersion: networking.k8s.io/v1
+# kind: NetworkPolicy
+# metadata:
+# name: n8n
+# namespace: n8n
+# labels:
+# app.kubernetes.io/name: n8n
+# app.kubernetes.io/instance: n8n
+# app.kubernetes.io/part-of: n8n
+# spec:
+# podSelector:
+# matchLabels:
+# app.kubernetes.io/name: n8n
+# app.kubernetes.io/instance: n8n
+# policyTypes:
+# - Ingress
+# - Egress
+# ingress:
+# - from:
+# - podSelector: {}
+# - from:
+# - namespaceSelector:
+# matchLabels:
+# kubernetes.io/metadata.name: traefik-system
+# egress:
+# - to:
+# - namespaceSelector: {}
+# podSelector:
+# matchLabels:
+# k8s-app: kube-dns
+# ports:
+# - port: 53
+# protocol: UDP
+# - to:
+# - ipBlock:
+# cidr: 0.0.0.0/0
+# ports:
+# - port: 443
+# - to:
+# - podSelector: {}
diff --git a/projects/maison/src/apps/n8n/n8n.httproute.yaml b/projects/maison/src/apps/n8n/n8n.httproute.yaml
new file mode 100644
index 00000000..4ba7abd0
--- /dev/null
+++ b/projects/maison/src/apps/n8n/n8n.httproute.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: n8n-websecure
+ namespace: n8n
+spec:
+ parentRefs:
+ - name: default
+ namespace: default
+ hostnames:
+ - n8n.chezmoi.sh
+ rules:
+ - backendRefs:
+ - name: n8n
+ port: 80
diff --git a/projects/maison/src/apps/n8n/n8n.vpn.yaml b/projects/maison/src/apps/n8n/n8n.vpn.yaml
new file mode 100644
index 00000000..27645d3a
--- /dev/null
+++ b/projects/maison/src/apps/n8n/n8n.vpn.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: n8n-tailscale
+ namespace: n8n
+spec:
+ defaultBackend:
+ service:
+ name: n8n
+ port:
+ number: 80
+ ingressClassName: tailscale
+ tls:
+ - hosts:
+ - n8n
diff --git a/projects/maison/src/apps/n8n/namespace.yaml b/projects/maison/src/apps/n8n/namespace.yaml
new file mode 100644
index 00000000..95a26b0b
--- /dev/null
+++ b/projects/maison/src/apps/n8n/namespace.yaml
@@ -0,0 +1,5 @@
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: n8n
diff --git a/projects/maison/src/infrastructure/crossplane/aws.iam.n8n.yaml b/projects/maison/src/infrastructure/crossplane/aws.iam.n8n.yaml
new file mode 100644
index 00000000..a2ac3214
--- /dev/null
+++ b/projects/maison/src/infrastructure/crossplane/aws.iam.n8n.yaml
@@ -0,0 +1,98 @@
+# AWS User for Authelia
+#
+# Description:
+# These resources will create an AWS IAM User with the necessary permissions
+# to send emails from the domain chezmoi.sh.
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: Policy
+metadata:
+ annotations:
+ crossplane.io/external-name: AutheliaSESSender
+ name: maison.chezmoi.sh-amazonses-n8n
+ namespace: kubevault-kvstore
+spec:
+ forProvider:
+ path: /maison.chezmoi.sh/
+ policy: |
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowSendingEmails",
+ "Effect": "Allow",
+ "Action": [
+ "ses:SendEmail",
+ "ses:SendRawEmail"
+ ],
+ "Resource": "arn:aws:ses:us-east-1:*:identity/*"
+ }
+ ]
+ }
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: User
+metadata:
+ annotations:
+ crossplane.io/external-name: n8n
+ name: maison.chezmoi.sh-amazonses-n8n
+ namespace: kubevault-kvstore
+spec:
+ forProvider:
+ path: /maison.chezmoi.sh/
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: UserPolicyAttachment
+metadata:
+ name: maison.chezmoi.sh-amazonses-n8n
+ namespace: kubevault-kvstore
+spec:
+ forProvider:
+ policyArnRef:
+ name: maison.chezmoi.sh-amazonses-n8n
+ userRef:
+ name: maison.chezmoi.sh-amazonses-n8n
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: AccessKey
+metadata:
+ name: maison.chezmoi.sh-amazonses-n8n
+ namespace: kubevault-kvstore
+spec:
+ forProvider:
+ userRef:
+ name: maison.chezmoi.sh-amazonses-n8n
+ writeConnectionSecretToRef:
+ name: apps-n8n-aws-ses
+ namespace: kubevault-kvstore
+---
+# trunk-ignore-all(trivy/KSV113,checkov/CKV2_K8S_5): accessing to this secret is required
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: kubevault:kubernetes.maison.chezmoi.sh:n8n-ses
+ namespace: kubevault-kvstore
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - secrets
+ resourceNames:
+ - apps-n8n-aws-ses
+ verbs:
+ - get
+ - list
+ - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: kubevault:kubernetes.maison.chezmoi.sh:n8n-ses
+ namespace: kubevault-kvstore
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: kubevault:kubernetes.maison.chezmoi.sh:n8n-ses
+subjects:
+ - kind: ServiceAccount
+ name: kubernetes.maison.chezmoi.sh
diff --git a/projects/maison/src/infrastructure/crossplane/kustomization.yaml b/projects/maison/src/infrastructure/crossplane/kustomization.yaml
index b111fc2f..d1c10c6e 100644
--- a/projects/maison/src/infrastructure/crossplane/kustomization.yaml
+++ b/projects/maison/src/infrastructure/crossplane/kustomization.yaml
@@ -8,3 +8,6 @@ resources:
# Cloudflare credentials
- cloudflare.iam.external-dns.yaml
- cloudflare.iam.cert-manager.yaml
+
+ # AWS IAM roles for n8n
+ - aws.iam.n8n.yaml