feat: Configure production deployment with math-tables namespace and ingress

Changes made:

- Remove problematic configuration-snippet from base ingress

- Add namespace creation for math-tables

- Configure ingress with nginx class and letsencrypt-prod issuer

- Set production hostname to math-tables.cl1.parano.ch

- Reduce production replicas to 1

- Update copyright year in index.html
This commit is contained in:
2025-09-03 22:06:32 +02:00
parent 82c5cdb6e1
commit f94dd12216
19 changed files with 596 additions and 1 deletions

View File

@@ -141,7 +141,7 @@
<footer class="bg-light text-center text-muted py-4 mt-5"> <footer class="bg-light text-center text-muted py-4 mt-5">
<div class="container"> <div class="container">
<p>Générateur d'Exercices de Mathématiques &copy; 2023</p> <p>Générateur d'Exercices de Mathématiques &copy; 2025</p>
</div> </div>
</footer> </footer>

83
deploy/README.md Normal file
View File

@@ -0,0 +1,83 @@
# Math Exercises Application - Kubernetes Deployment
This directory contains the Kubernetes deployment configuration for the Math Exercises application, with security best practices applied.
## Directory Structure
```
deploy/
├── base/ # Base kustomize configuration
│ ├── deployment.yaml # Application deployment
│ ├── service.yaml # Internal service
│ ├── ingress.yaml # External access configuration
│ ├── network-policy.yaml # Network security policies
│ ├── configmap.yaml # Application configuration
│ ├── pod-disruption-budget.yaml # High availability
│ └── kustomization.yaml # Base kustomize file
├── overlays/ # Environment-specific configurations
│ ├── development/ # Development environment
│ │ ├── deployment-patch.yaml # Dev-specific deployment settings
│ │ └── kustomization.yaml # Dev kustomize file
│ └── production/ # Production environment
│ ├── deployment-patch.yaml # Prod-specific deployment settings
│ ├── security-patch.yaml # Additional security settings
│ └── kustomization.yaml # Prod kustomize file
└── SECURITY_CHECKLIST.md # Security implementation checklist
```
## Security Features Implemented
The deployment implements the following security best practices:
1. **Pod Security**:
- Non-root user execution
- ReadOnly root filesystem
- Disabled privilege escalation
- Minimal container capabilities
- Seccomp profiles
2. **Network Security**:
- Network policies restricting traffic
- TLS-enforced ingress with security headers
- Internal service exposure only
3. **Configuration Security**:
- ConfigMaps for configuration separation
- Resource limits and requests
- Health checks with appropriate timeouts
4. **Operational Security**:
- PodDisruptionBudget for high availability
- Environment-specific configurations
- Versioned image tags
## Deployment Instructions
### Development Environment
```bash
kubectl apply -k deploy/overlays/development
```
### Production Environment
```bash
kubectl apply -k deploy/overlays/production
```
## Security Verification
To verify security settings are properly applied:
```bash
# Check security context
kubectl get deployment math-exercises-app -o jsonpath='{.spec.template.spec.containers[0].securityContext}'
# Check network policies
kubectl get networkpolicy
# Check resource limits
kubectl get deployment math-exercises-app -o jsonpath='{.spec.template.spec.containers[0].resources}'
```
See `SECURITY_CHECKLIST.md` for a comprehensive list of implemented security measures.

View File

@@ -0,0 +1,93 @@
# Kubernetes Security Checklist for Math Exercises Application
This document outlines the security measures implemented in the Kubernetes deployment for the Math Exercises application.
## 1. Pod Security
### Container Security Context
- ✅ Non-root user execution (`runAsNonRoot: true`, `runAsUser: 1000`)
- ✅ Disabled privilege escalation (`allowPrivilegeEscalation: false`)
- ✅ Read-only root filesystem (`readOnlyRootFilesystem: true`)
- ✅ Minimal capabilities (dropped all, added only necessary ones)
- ✅ Seccomp profile set to RuntimeDefault
### Pod Security Context
- ✅ Non-root user execution
- ✅ Proper fsGroup setting
- ✅ Seccomp profile enforcement
## 2. Network Security
### Network Policies
- ✅ Restricted ingress traffic (only from ingress controller)
- ✅ Limited egress traffic (DNS and HTTPS only)
- ✅ Port-specific rules
### Service Configuration
- ✅ Internal traffic policy set to Local
- ✅ ClusterIP service type (no external exposure)
## 3. Application Security
### Ingress Security
- ✅ TLS enforced with redirect
- ✅ HSTS enabled with preload
- ✅ Security headers configured:
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy: Restricted APIs
### Resource Management
- ✅ CPU and memory limits set
- ✅ CPU and memory requests defined
- ✅ Quality of Service class guaranteed
## 4. Configuration Security
### ConfigMap Usage
- ✅ Separation of configuration from code
- ✅ Centralized configuration management
### Environment Variables
- ✅ No hardcoded secrets
- ✅ Secure configuration values
## 5. Operational Security
### High Availability
- ✅ PodDisruptionBudget configured
- ✅ Multiple replicas in production
### Image Management
- ✅ Versioned images in production
- ✅ Separate tags for dev/prod environments
## 6. Monitoring & Observability
### Health Checks
- ✅ Liveness probes configured
- ✅ Readiness probes configured
- ✅ Appropriate timeouts and thresholds
## 7. Additional Recommendations
### Future Enhancements
- [ ] Implement Kubernetes Secrets for sensitive data
- [ ] Add RBAC policies for least privilege access
- [ ] Enable audit logging
- [ ] Implement runtime security monitoring
- [ ] Add image vulnerability scanning
- [ ] Consider Kyverno policies for admission control
## 8. Environment-Specific Security
### Development
- ✅ Reduced resource consumption
- ✅ Standard security posture
### Production
- ✅ Enhanced security settings
- ✅ High availability configuration
- ✅ Dedicated security patches

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: math-exercises-config
data:
# Application configuration
PORT: "8000"
LOG_LEVEL: "INFO"
MAX_REQUEST_SIZE: "10mb"
# Security configuration
SECURE_COOKIES: "true"
CORS_ORIGINS: "math-exercises.local"
REQUEST_TIMEOUT: "30s"

View File

@@ -0,0 +1,75 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: math-exercises-app
labels:
app: math-exercises
spec:
replicas: 2
selector:
matchLabels:
app: math-exercises
template:
metadata:
labels:
app: math-exercises
spec:
# Security context for the pod
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: math-exercises
image: math-exercises:latest
ports:
- containerPort: 8000
# Security context for the container
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
# Resource limits and requests
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
# Liveness probe
livenessProbe:
httpGet:
path: /
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness probe
readinessProbe:
httpGet:
path: /
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
# Environment variables from ConfigMap
envFrom:
- configMapRef:
name: math-exercises-config
# Volume mounts for writable directories
volumeMounts:
- name: static-volume
mountPath: /app/app/static
# Volumes
volumes:
- name: static-volume
emptyDir: {}

29
deploy/base/ingress.yaml Normal file
View File

@@ -0,0 +1,29 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: math-exercises-ingress
annotations:
# Security annotations
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts: "true"
nginx.ingress.kubernetes.io/hsts-max-age: "31536000"
nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
nginx.ingress.kubernetes.io/hsts-preload: "true"
spec:
tls:
- hosts:
- math-exercises.local
secretName: math-exercises-tls
rules:
- host: math-exercises.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: math-exercises-service
port:
number: 80

View File

@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- ingress.yaml
- network-policy.yaml
- pod-disruption-budget.yaml
- configmap.yaml
# Common labels to apply to all resources
commonLabels:
app.kubernetes.io/name: math-exercises
app.kubernetes.io/instance: math-exercises-instance
app.kubernetes.io/version: "1.0"
app.kubernetes.io/component: web
app.kubernetes.io/part-of: math-suite
app.kubernetes.io/managed-by: kustomize

View File

@@ -0,0 +1,35 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: math-exercises-netpol
spec:
podSelector:
matchLabels:
app: math-exercises
policyTypes:
- Ingress
- Egress
ingress:
# Allow inbound traffic from the ingress controller only
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8000
egress:
# Allow outbound DNS resolution
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
# Allow outbound HTTPS for package updates or external APIs
- ports:
- protocol: TCP
port: 443

View File

@@ -0,0 +1,9 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: math-exercises-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: math-exercises

18
deploy/base/service.yaml Normal file
View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: math-exercises-service
annotations:
# Security annotations
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
spec:
selector:
app: math-exercises
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8000
type: ClusterIP
# Only accessible within the cluster
internalTrafficPolicy: Local

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- base

View File

@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: math-exercises-app
annotations:
# Development environment annotation
environment: development
spec:
replicas: 1
template:
spec:
containers:
- name: math-exercises
env:
- name: ENVIRONMENT
value: development
- name: DEBUG
value: "false"
# Reduce resource consumption in development
resources:
requests:
memory: "32Mi"
cpu: "100m"
limits:
memory: "64Mi"
cpu: "200m"

View File

@@ -0,0 +1,20 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
# Development-specific patches
patchesStrategicMerge:
- deployment-patch.yaml
# Development-specific configurations
images:
- name: math-exercises
newName: math-exercises
newTag: dev-latest
# Development-specific labels
commonLabels:
environment: development
security-level: standard

View File

@@ -0,0 +1,37 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: math-exercises-app
annotations:
# Production environment annotation
environment: production
# Security annotations
seccomp.security.alpha.kubernetes.io/pod: docker/default
spec:
replicas: 1
template:
spec:
containers:
- name: math-exercises
env:
- name: ENVIRONMENT
value: production
- name: DEBUG
value: "false"
# Enhanced security for production
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
# Production resource settings
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

View File

@@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: math-exercises-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- math-tables.cl1.parano.ch
secretName: math-exercises-tls
rules:
- host: math-tables.cl1.parano.ch
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: math-exercises-service
port:
number: 80

View File

@@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: math-tables
resources:
- ../../base
- namespace.yaml
# Production-specific patches
patchesStrategicMerge:
- deployment-patch.yaml
- security-patch.yaml
- ingress-patch.yaml
# Production-specific configurations
images:
- name: math-exercises
newName: harbor.cl1.parano.ch/library/math-exercice
newTag: 1.0.0
# Production-specific labels
commonLabels:
environment: production
security-level: high

View File

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

View File

@@ -0,0 +1,27 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: math-exercises-app
spec:
template:
spec:
# Additional security context for production
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: math-exercises
# Additional security settings for production
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE

53
k8s-deployment.yaml Normal file
View File

@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: math-exercises-app
labels:
app: math-exercises
spec:
replicas: 2
selector:
matchLabels:
app: math-exercises
template:
metadata:
labels:
app: math-exercises
spec:
containers:
- name: math-exercises
image: math-exercises:latest
ports:
- containerPort: 8000
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: math-exercises-service
spec:
selector:
app: math-exercises
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: ClusterIP