first commit

This commit is contained in:
Your Name
2026-01-18 18:00:41 +01:00
parent 973dddce86
commit 5ca040819f
14 changed files with 9693 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.aider*

4
00-namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: wordpress

22
01-cnpg-cluster.yaml Normal file
View File

@@ -0,0 +1,22 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: wordpress-db
namespace: wordpress
spec:
instances: 2
storage:
size: 20Gi
storageClass: longhorn-fast
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "750m"
bootstrap:
initdb:
database: postgres
affinity:
enablePodAntiAffinity: false

View File

@@ -0,0 +1,17 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: wordpress-security-headers
namespace: wordpress
spec:
headers:
customResponseHeaders:
X-Frame-Options: "DENY"
X-Content-Type-Options: "nosniff"
X-XSS-Protection: "1; mode=block"
X-Powered-By: "" # Removes the X-Powered-By header
# HSTS (Strict-Transport-Security) is often configured at the IngressRoute level or with a dedicated HSTS middleware.
# For simplicity, I'm keeping it commented out here but it can be added if needed.
# stsSeconds: 31536000 # 1 year
# stsIncludeSubdomains: true
# stsPreload: true

111
03-network-policies.yaml Normal file
View File

@@ -0,0 +1,111 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: wordpress
spec:
podSelector: {} # Selects all pods in the namespace
policyTypes:
- Ingress
- Egress
# This policy creates a default-deny state.
# Specific policies below will allow necessary traffic.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-traefik-ingress
namespace: wordpress
spec:
podSelector: {} # Apply to all pods in the namespace
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: traefik # Assuming Traefik pods have this label
# If Traefik is in a different namespace, specify that namespace:
# namespaceSelector:
# matchLabels:
# kubernetes.io/metadata.name: traefik # Example label for Traefik namespace
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-wordpress-to-cnpg
namespace: wordpress
spec:
podSelector:
matchLabels:
app: wordpress # Label for WordPress pods
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: cloudnativepg # Label for CNPG pods
ports:
- protocol: TCP
port: 5432 # Default PostgreSQL port
# Allow DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-wordpress-ingress # Fixed syntax for ingress rule
namespace: wordpress
spec:
podSelector:
matchLabels:
app: wordpress # Label for WordPress pods
policyTypes:
- Ingress
ingress:
- from: [] # Empty from means allow from all sources (will be restricted by Traefik Ingress)
ports:
- protocol: TCP
port: 80
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-apiserver
namespace: wordpress
spec:
podSelector:
matchLabels:
cnpg.io/cluster: wordpress-db # Targets all components of the wordpress-db cluster
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.96.0.1/32 # Kubernetes API Server IP
ports:
- protocol: TCP
port: 443

42
GEMINI.md Normal file
View File

@@ -0,0 +1,42 @@
# Role
Sei un esperto SRE e Security Architect Kubernetes. Genera manifest YAML per un'architettura WordPress multi-tenant ultra-sicura.
# Context
- Namespace: `wordpress`.
- Ingress Controller: **Traefik** (usando le CRD `IngressRoute` e `Middleware`).
- Architettura: Multi-tenant (1 Pod, 1 Deployment, 1 PVC per ogni sito).
- Storage: `longhorn-fast`.
- Database: **CloudNativePG (CNPG)** (Un cluster centrale, database/user dedicati per sito).
# Requirements & Security Hardening
Genera i manifest includendo:
1. **Traefik IngressRoute & Middlewares**:
- Definisci un `Middleware` di sicurezza standard: HSTS, rimozione header `X-Powered-By`, protezione XSS, `nosniff`, e restrizioni `frameDeny`.
- Per ogni sito, crea un `IngressRoute` che punta al servizio WordPress.
- Configura il TLS tramite `secretName` gestito da cert-manager.
2. **CloudNativePG (CNPG) Setup**:
- Definisci un `Cluster` PostgreSQL robusto.
- Per ogni nuovo sito WordPress, genera la risorsa `Database` e `User` di CNPG affinché ogni sito abbia le proprie credenziali isolate.
3. **WordPress Hardening (Per Sito)**:
- Immagine: `wordpress:php8.2-fpm-alpine`.
- **SecurityContext**: `runAsNonRoot: true`, `allowPrivilegeEscalation: false`, `readOnlyRootFilesystem: true`.
- **Volumes**:
- PVC `longhorn-fast` montato su `/var/www/html/wp-content`.
- `emptyDir` per `/tmp`, `/var/run`, e le cache di PHP/Nginx per supportare il filesystem in sola lettura.
4. **Network Isolation**:
- `NetworkPolicy` di tipo "Default Deny" nel namespace.
- Regole specifiche per permettere a Traefik di parlare con i Pod WordPress e ai Pod WordPress di parlare solo con il Cluster CNPG.
5. **Resource Limits**:
- CPU: 200m-500m, RAM: 256Mi-512Mi per ogni istanza WordPress.
# Output Format
Fornisci i manifest separati o raggruppati, pronti per essere applicati. Includi una sezione "Template Variabili" per permettermi di scalare facilmente l'aggiunta di nuovi siti.
# Constraints
- Usa solo HTTPS (redirect automatico gestito da Traefik).
- Isolamento totale tra i siti: nessun Pod deve poter vedere il PVC di un altro.

0
README.md Normal file
View File

View File

@@ -0,0 +1,18 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-apiserver
namespace: wordpress
spec:
podSelector:
matchLabels:
cnpg.io/cluster: wordpress-db # Targets all components of the wordpress-db cluster
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.96.0.1/32 # Kubernetes API Server IP
ports:
- protocol: TCP
port: 443

File diff suppressed because it is too large Load Diff

30
traefik.crt Normal file
View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFETCCAvmgAwIBAgIUMDt3pOo2RwsQAXk85yPNqSEbQEcwDQYJKoZIhvcNAQEL
BQAwGDEWMBQGA1UEAwwNdHJhZWZpay5sb2NhbDAeFw0yNjAxMTQxNTExMzRaFw0y
NzAxMTQxNTExMzRaMBgxFjAUBgNVBAMMDXRyYWVmaWsubG9jYWwwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDzXfA5UbbiUUaN0syLqefYdwipB3esJ+8Q
lTT6I2EahM395Lcnqmd6Qfrgaao0AyQ42eYQT65MxACw4UDhg7FxIgDvPDoClnW1
jyL4rwLA9I2fj83xhOwemvwPPeeSPkJqAEHa9stazLezEo6vDcdtB2clobcs5uQJ
eJs4Ne27TVYOOvo3BF+s7eb4sBz3EwRWAZQ51+ZAayMP3E9XEWUzbAYCjA/yyQ6X
fBVJdHJQThBK5tFvexO7G5y4ouIsyoAEzxk+960pbFBXMUUL1hqWX2w1BebC9TNC
XOaDwMxBooJPN9JAmSUr7gSI7fLpGDf3x5gZAQryvRnSUkCbyn0Kz2e/D4Vp1kUu
0aJ2DiPE81561Hdu7xJl7545juTxHBy9+XwBrxiISB3d1djCiezsc10FrPhL1PWM
yowihKwVuTLbDQw4ZogGV+jk6k6+99kyRMJjLEd/e/GAX61K50dUuwslyacwZsc1
XR9Br+zdzpqveBt4XAry2MlBF0VcLuan3wM7edywKcurKbVaK/fJsZTF2Ih26DK3
ZI8D23mV8bv4eR7vFNTvFGSiHeUrgtV6AX63Vgo9cse+UnhXHri3cFdtVZK8eUBE
H9xglGxeff4xKqF6Noc48prre41eK397llT2tznreYnM6S4n3Y01lfmFTZFd48ws
bMhYKFO/RQIDAQABo1MwUTAdBgNVHQ4EFgQURlSlwEmkAXn6rWnxeZstYGTMKUow
HwYDVR0jBBgwFoAURlSlwEmkAXn6rWnxeZstYGTMKUowDwYDVR0TAQH/BAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAgEAL5K8ZzauZy/9mOAgE1OKQ5ZLekz372D+OI93
vED+r+qf8pRCjosBb0Ag2cLO2H5Qnj0If72c3GZOUp+H4t1PQ+T9vji7Hr6fy6sj
M6quYOh6zIR5VK885K2EYyuVWbRE+uces06b9tVceeLgVrUjbuK7+0C0qU8x8L9d
FqXK8p2leIwawDYrNGTDnr+ZsOK09nN3iGnU5XW7WZnfmWar9v2qlkTlJywyaNyU
NmuEO5LxRfqUWINabxKfltssxGe74ku/ot2BJRNUuIM6lt+fH1bwrjqaxOUN6mW7
Va4OIat3IBsGZuALSyYiXq9Lg+Ec2DmV95j/wf8iQtKzSUdU+U3mw8SxSwSsrLO3
B1dVtbZKOSflJkLb8gfraz7XJpL8WuQ0n4rH2GL28HVJbNh/1ytlA4tDFWNp4Onv
Y4+Jy7mEPtB+bV1NHD5KQfYFwyBRqGxL7BB9F5VJSH9+R7Rc7HKlaOjcUzyq3SnL
P10Jsv3I68cuDmwm4CHNamEVYmipKhhncn8k06uHk9Xut0aKZDJ7OfMr5G6NQBEQ
/0Pf4uCKt3KfWoT+4vHy2PYzXQSTABzqGAC27Xe1ZVOudllLDiT//bFMORYx8nRn
h+P+CRbODiPbZedK0tsjO8+ZPCFGxFpQhVf7a8MRDXl0FG1GlHA73nKiaTAbEp7b
OrnPKRk=
-----END CERTIFICATE-----

52
traefik.key Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
REsrP+0hR8mCJm2lhpqPn07LFzAqmfIg
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: virtualinsanity-db-secret
namespace: wordpress
type: Opaque
data:
password: "Y2V2MTRqODQ/N0hZckh3Ww=="
dbname: "dmlydHVhbGluc2FuaXR5ZGI="
username: "d2VnYXBwY29ubmVjdA=="

View File

@@ -0,0 +1,6 @@
apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
name: virtualinsanity-db
namespace: wordpress
spec: {}

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: virtualinsanity-wp-content
namespace: wordpress
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn-fast
resources:
requests:
storage: 20Gi