chore: build
This commit is contained in:
@@ -815,6 +815,7 @@ const veleroNamespace = "velero"
|
||||
var (
|
||||
veleroScheduleGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "schedules"}
|
||||
veleroBackupGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "backups"}
|
||||
veleroBackupRepoGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "backuprepositories"}
|
||||
)
|
||||
|
||||
// demoBackupScheduleName : nom du Schedule Velero dédié à ce namespace de
|
||||
@@ -857,14 +858,24 @@ func (h *HelmProvisioner) ensureDemoBackupSchedule(namespace string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteDemoBackups supprime le Schedule Velero de cette démo ainsi que
|
||||
// toutes les sauvegardes déjà prises par ce planning (la suppression d'un
|
||||
// Backup déclenche le nettoyage asynchrone des données Kopia associées côté
|
||||
// Velero — pas de suppression directe dans le bucket S3, qui risquerait de
|
||||
// casser le dépôt Kopia partagé par les autres démos). Appelée depuis
|
||||
// Teardown (expiration TTL et destruction forcée passent toutes les deux
|
||||
// par ce même chemin) et lors d'une migration premium réussie (l'ancien
|
||||
// namespace disparaît, son planning de sauvegarde n'a plus de sens).
|
||||
// deleteDemoBackups supprime le Schedule Velero de cette démo, toutes les
|
||||
// sauvegardes déjà prises par ce planning, et le BackupRepository associé
|
||||
// (la suppression d'un Backup déclenche le nettoyage asynchrone des données
|
||||
// Kopia associées côté Velero — pas de suppression directe dans le bucket
|
||||
// S3, qui risquerait de casser le dépôt Kopia partagé par les autres
|
||||
// démos). Appelée depuis Teardown (expiration TTL et destruction forcée
|
||||
// passent toutes les deux par ce même chemin) et lors d'une migration
|
||||
// premium réussie (l'ancien namespace disparaît, son planning de sauvegarde
|
||||
// n'a plus de sens).
|
||||
//
|
||||
// Le BackupRepository (l'objet qui référence le dépôt Kopia du namespace,
|
||||
// nommé "<namespace>-default-kopia") n'est PAS supprimé automatiquement par
|
||||
// Velero quand ses Backup disparaissent — sans ce nettoyage explicite, il
|
||||
// reste indéfiniment et Velero continue de lancer des jobs de maintenance
|
||||
// périodiques dessus (kopia-maintain-job) pour un dépôt qui ne sert plus à
|
||||
// rien. Supprimer l'objet ne touche pas aux données déjà écrites dans le
|
||||
// bucket S3 (même logique que pour les Backup ci-dessus), juste le
|
||||
// bookkeeping Velero.
|
||||
func (h *HelmProvisioner) deleteDemoBackups(namespace string) error {
|
||||
name := demoBackupScheduleName(namespace)
|
||||
|
||||
@@ -886,6 +897,13 @@ func (h *HelmProvisioner) deleteDemoBackups(namespace string) error {
|
||||
if err != nil && !k8sErrors.IsNotFound(err) {
|
||||
return fmt.Errorf("suppression planning %s: %w", name, err)
|
||||
}
|
||||
|
||||
repoName := namespace + "-default-kopia"
|
||||
err = h.dynamicClient.Resource(veleroBackupRepoGVR).Namespace(veleroNamespace).
|
||||
Delete(context.Background(), repoName, metav1.DeleteOptions{})
|
||||
if err != nil && !k8sErrors.IsNotFound(err) {
|
||||
return fmt.Errorf("suppression backuprepository %s: %w", repoName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
# Identifiants à récupérer dans le Hub Beszel : Add System > Universal token.
|
||||
# Le token universel expire au bout d'1h mais permet l'auto-enregistrement de
|
||||
# TOUS les agents du DaemonSet sans les déclarer un par un dans le Hub ; une
|
||||
# fois qu'un agent s'est enregistré, il garde son identité même après
|
||||
# l'expiration du token (donc pas besoin de le renouveler après coup).
|
||||
# Les nœuds k3s ne sont pas sur le VPN (voir omnex/ansible/inventory/host.ini)
|
||||
# et le dashboard Beszel (8090) doit rester accessible uniquement via le VPN
|
||||
# (10.0.0.0/24) — donc pas question de pointer HUB_URL dessus. Le Hub expose
|
||||
# à la place un port dédié 10002 (nginx, restreint aux 4 IP publiques des
|
||||
# nœuds k3s-prod + chemin /api/ uniquement — voir
|
||||
# ansible-mln/monitoring/security/nginx/nginx.conf et
|
||||
# firewall-monitoring-uber.sh) : c'est CE port que les agents utilisent pour
|
||||
# s'auto-enregistrer, jamais le dashboard.
|
||||
#
|
||||
# TOKEN : token universel généré dans le Hub (Add System > Universal token,
|
||||
# expire au bout d'1h mais un agent déjà enregistré garde son identité).
|
||||
# KEY : clé publique SSH du Hub (une seule pour tous les agents, quel que
|
||||
# soit le système) — même valeur que celle déjà utilisée par l'agent
|
||||
# s3-uber (voir ansible-mln/monitoring/s3-backup/docker-compose.yml).
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -10,6 +19,6 @@ metadata:
|
||||
namespace: monitoring
|
||||
type: Opaque
|
||||
stringData:
|
||||
HUB_URL: "" # ex: https://beszel.exemple.com
|
||||
HUB_URL: "https://185.103.167.138:10002"
|
||||
TOKEN: "" # token universel généré dans le Hub
|
||||
KEY: "" # clé publique SSH affichée par le Hub
|
||||
KEY: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwRVn66crRDX5iL0bxNOnrp3OhTiXHKs+COx/bo5vmQ beszel-agent"
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# Isolation réseau du namespace monitoring (beszel-agent) — deny-by-default +
|
||||
# allowlist :
|
||||
# - Egress : HTTPS sortant vers le Hub (HUB_URL, hôte externe arbitraire —
|
||||
# voir beszel-agent-secret.yml) pour l'auto-enregistrement au démarrage.
|
||||
# - Egress : HTTPS sortant vers le Hub sur son port dédié agents (10002,
|
||||
# pas 8090/dashboard — voir beszel-agent-secret.yml et
|
||||
# ansible-mln/monitoring/security/nginx/nginx.conf) pour
|
||||
# l'auto-enregistrement au démarrage.
|
||||
# - Ingress : le Hub se connecte à l'agent en SSH sur le port LISTEN
|
||||
# (45876) pour récupérer les métriques — IP du Hub non fixe/connue
|
||||
# (10002) pour récupérer les métriques — IP du Hub non fixe/connue
|
||||
# d'avance, ouvert largement mais authentifié par TOKEN/KEY (voir
|
||||
# beszel-agent-secret.yml), pas par l'origine réseau.
|
||||
#
|
||||
@@ -14,7 +16,7 @@
|
||||
# GlobalNetworkPolicy Calico, une ressource différente, pour un enforcement
|
||||
# réel au niveau du nœud). Ce manifeste reste appliqué pour la correction
|
||||
# d'intention et si hostNetwork est retiré un jour, mais ne pas compter
|
||||
# dessus comme protection effective du port 45876 en l'état — un pare-feu
|
||||
# dessus comme protection effective du port 10002 en l'état — un pare-feu
|
||||
# hôte (iptables/nftables/ufw) ou une GlobalNetworkPolicy Calico est
|
||||
# nécessaire pour une vraie restriction.
|
||||
|
||||
@@ -43,7 +45,7 @@ spec:
|
||||
- from: []
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 45876
|
||||
port: 10002
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
@@ -86,4 +88,4 @@ spec:
|
||||
- 192.168.0.0/16
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
port: 10002
|
||||
|
||||
@@ -83,6 +83,13 @@ data:
|
||||
# mécanisme que docker/waf (omnex-prod).
|
||||
SecAuditLogParts ABIFHZ
|
||||
|
||||
# 911100 (REQUEST-911-METHOD-ENFORCEMENT) n'autorise par défaut que GET
|
||||
# HEAD POST OPTIONS — bloque tout DELETE/PUT/PATCH légitime de l'API
|
||||
# REST. Même correctif appliqué côté docker/waf/custom-rules.conf
|
||||
# (omnex-prod) et côté Coraza/Traefik (deploy/chart-gestion/traefik/
|
||||
# templates/middleware-waf.yaml).
|
||||
SecRuleRemoveById 911100
|
||||
|
||||
SecRule IP:BANNED "@eq 1" \
|
||||
"id:100000,phase:1,deny,status:403,log,\
|
||||
msg:'IP is banned'"
|
||||
|
||||
@@ -45,7 +45,7 @@ spec:
|
||||
name: beszel-agent-hub
|
||||
env:
|
||||
- name: LISTEN
|
||||
value: "45876"
|
||||
value: "10002"
|
||||
- name: SYSTEM_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
|
||||
@@ -137,6 +137,36 @@ roleRef:
|
||||
kind: ClusterRole
|
||||
name: omnex-namespace-manager
|
||||
---
|
||||
# "nodes" n'est pas un type namespaced : impossible de le scoper via un
|
||||
# RoleBinding par démo comme omnex-demo-workload-manager, d'où une
|
||||
# ClusterRole/ClusterRoleBinding dédiée. Portée strictement à "get" sur le
|
||||
# sous-type "nodes/proxy" — c'est tout ce dont checkPVCUsage a besoin
|
||||
# (voir alerts/resources.go:fetchNodeSummary, équivalent de
|
||||
# `kubectl get --raw /api/v1/nodes/<node>/proxy/stats/summary`) pour lire
|
||||
# le remplissage des PVC. Aucun accès en écriture, aucun accès aux autres
|
||||
# sous-ressources de Node.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: omnex-node-stats-reader
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: [nodes/proxy]
|
||||
verbs: [get]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: omnex-control-plane-node-stats
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: omnex-control-plane
|
||||
namespace: omnex-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: omnex-node-stats-reader
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
@@ -166,8 +196,8 @@ type: kubernetes.io/service-account-token
|
||||
# namespace fixe préexistant, pas un namespace de démo créé dynamiquement
|
||||
# par le control-plane — pas besoin du mécanisme "bind" utilisé pour
|
||||
# omnex-demo-workload-manager). Portée strictement limitée aux Schedule/
|
||||
# Backup Velero — aucun accès aux Secrets (dont cloud-credentials, la clé
|
||||
# du bucket S3) ni au reste du namespace velero.
|
||||
# Backup/BackupRepository Velero — aucun accès aux Secrets (dont
|
||||
# cloud-credentials, la clé du bucket S3) ni au reste du namespace velero.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -178,8 +208,10 @@ rules:
|
||||
# Un Schedule + les Backup qu'il crée par démo (voir
|
||||
# HelmProvisioner.ensureDemoBackupSchedule/deleteDemoBackups) — jamais
|
||||
# de wildcard multi-namespace, pour pouvoir supprimer les sauvegardes
|
||||
# d'UNE démo sans toucher aux autres.
|
||||
resources: [schedules, backups]
|
||||
# d'UNE démo sans toucher aux autres. backuprepositories : nettoyage du
|
||||
# dépôt Kopia du namespace détruit (deleteDemoBackups) — sans quoi
|
||||
# Velero continue de lancer des jobs de maintenance dessus indéfiniment.
|
||||
resources: [schedules, backups, backuprepositories]
|
||||
verbs: [get, list, watch, create, delete]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -61,7 +61,9 @@ export function Demos() {
|
||||
// Les démos passées en abonnement payant vivent désormais dans le
|
||||
// dashboard Premium (n'expirent plus, stockage persistant) — ne plus
|
||||
// les mélanger avec les démos d'essai ici.
|
||||
setDemos((res.items ?? []).filter((d) => d.type_abonnement !== 'premium'))
|
||||
setDemos(
|
||||
(res.items ?? []).filter((d) => d.type_abonnement !== 'premium' && d.status !== 'expired'),
|
||||
)
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && err.status === 401) navigate('/admin/login')
|
||||
else toast({ status: 'error', title: 'Chargement des démos impossible' })
|
||||
|
||||
@@ -56,7 +56,9 @@ export function PremiumDemos() {
|
||||
const load = useCallback(async () => {
|
||||
try {
|
||||
const res = await api.listDemos()
|
||||
setDemos((res.items ?? []).filter((d) => d.type_abonnement === 'premium'))
|
||||
setDemos(
|
||||
(res.items ?? []).filter((d) => d.type_abonnement === 'premium' && d.status !== 'expired'),
|
||||
)
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && err.status === 401) navigate('/admin/login')
|
||||
else toast({ status: 'error', title: 'Chargement des démos impossible' })
|
||||
|
||||
Reference in New Issue
Block a user