Files
CloudOps/k8s/management-platform-deployment.yaml
root f3f08c3ef6 Give management-platform a scoped ServiceAccount for k8s backup/restore
The pod running app.py had no kubectl binary and only a read-only SA
(management-platform-viewer-sa) — backup-k8s-apps.sh/restore-k8s-apps.sh
could never actually run from inside it. Adds:

- management-platform-backup-role (ClusterRole, bound via RoleBinding only
  in n8n/odoo/mautic/nextcloud/erpnext — not cluster-wide): get/list/watch
  on pods/deployments/configmaps/ingresses/PVCs, pods/exec create, pods
  create+delete (needed for restore's populate-before-scale-up loader pod),
  secrets get/list/update/patch, deployments/scale update/patch only (no
  write on full Deployment/Service/ConfigMap/Ingress specs).
- management-platform-sa, replacing management-platform-viewer-sa as the
  pod's identity — inherits the old viewer-role's read-only bindings too
  (retargeted in management-platform-viewer-rbac.yaml) so the existing
  cluster-view page keeps working under one SA.
- k3s binary hostPath-mounted read-only into the pod (same pattern as the
  Jenkins agent's docker-cli container), so `k3s kubectl` is available
  where no separate kubectl binary exists.

Both scripts updated to fall back to k3s kubectl when no kubectl is on
PATH, and to use /proc/meminfo instead of `free` for the resource-safety
check (not present in the pod's minimal image). Also fixes a real issue
found while live-testing this from inside the pod: the pod's pre-existing
/root hostPath mount also exposes the host's own admin ~/.kube/config,
which k3s kubectl was silently preferring over the scoped SA token —
forcing --kubeconfig=/dev/null in both scripts closes that.

Verified end-to-end from inside the actual management-platform pod:
manifests/secret/DB-dump/PVC-data backup for n8n succeeds under the new
SA's scoped permissions, and a kube-system access attempt is correctly
rejected (Forbidden) once the kubeconfig leak is closed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 11:30:03 +02:00

78 lines
1.9 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: management-platform
namespace: management-platform
labels:
app: management-platform
app.kubernetes.io/managed-by: navitrends-pfe-migration
owner: ameni-boukattaya
spec:
replicas: 1
revisionHistoryLimit: 10
strategy:
type: Recreate
selector:
matchLabels:
app: management-platform
template:
metadata:
labels:
app: management-platform
app.kubernetes.io/managed-by: navitrends-pfe-migration
owner: ameni-boukattaya
spec:
serviceAccountName: management-platform-sa
containers:
- name: management-platform
image: management-platform:latest
imagePullPolicy: Never
ports:
- containerPort: 5000
protocol: TCP
env:
- name: HOSTNAME
value: vmi3024229
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-sock
- mountPath: /root
name: root-dir
- mountPath: /etc/passwd
name: etc-passwd
readOnly: true
- mountPath: /etc/shadow
name: etc-shadow
readOnly: true
- mountPath: /app/config.py
name: config-py
readOnly: true
- mountPath: /usr/local/bin/k3s
name: k3s-bin
readOnly: true
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket
- name: root-dir
hostPath:
path: /root
type: Directory
- name: etc-passwd
hostPath:
path: /etc/passwd
type: File
- name: etc-shadow
hostPath:
path: /etc/shadow
type: File
- name: config-py
hostPath:
path: /root/management-platform/config.py
type: File
- name: k3s-bin
hostPath:
path: /usr/local/bin/k3s
type: File