From 8b2f650e505148850d5a6aa9de5d8dc6e8802802 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Dolbeau Date: Fri, 29 May 2026 14:08:48 +0200 Subject: [PATCH 1/3] fix(helm): apiserverExternalEgress list + serverName comment + doc (v0.2.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix apiserverExternalEgress: was a single object, now a list — allows defining multiple egress NetworkPolicy rules from vtom-apiserver to external endpoints (e.g. MFT on a remote cluster) - Clarify serverName comment: name sent to agents to report job status back to the server; must point to the vtom-server LoadBalancer hostname (K8s service name unreachable by external agents) - Add MetalLB prerequisite note in on-premise prerequisites (README EN + FR) Co-Authored-By: Claude Sonnet 4.6 --- charts/visual-tom/Chart.yaml | 2 +- charts/visual-tom/README-fr.md | 517 ++++++++++++++++++ charts/visual-tom/README.md | 517 ++++++++++++++++++ .../templates/common/networkpolicy.yaml | 14 +- charts/visual-tom/values-client-template.yaml | 33 +- charts/visual-tom/values.yaml | 13 +- 6 files changed, 1064 insertions(+), 32 deletions(-) create mode 100644 charts/visual-tom/README-fr.md create mode 100644 charts/visual-tom/README.md diff --git a/charts/visual-tom/Chart.yaml b/charts/visual-tom/Chart.yaml index c535a41..b82f61f 100644 --- a/charts/visual-tom/Chart.yaml +++ b/charts/visual-tom/Chart.yaml @@ -7,7 +7,7 @@ description: > type: application # Chart version (follows SemVer). Increment on every chart change. -version: 0.2.2 +version: 0.2.3 # Reference application version (VTOM). ITC, ITM and MFT versions are defined in values.yaml. appVersion: "7.3.2c" diff --git a/charts/visual-tom/README-fr.md b/charts/visual-tom/README-fr.md new file mode 100644 index 0000000..cfd5c2f --- /dev/null +++ b/charts/visual-tom/README-fr.md @@ -0,0 +1,517 @@ +# Visual TOM — Chart Helm Kubernetes +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)  +[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md) + +Ce dépôt fournit un chart Helm pour déployer **Visual TOM (Absyss)** et ses produits associés sur Kubernetes : + +- **VTOM** — Ordonnanceur (core) +- **ITC** — Visual TOM User Portal +- **ITM** — Visual IT Messenger +- **MFT** — Visual TOM Managed File Transfer + +Cibles validées : + +| Environnement | Statut | +|---|---| +| Azure AKS | ✅ Validé | +| GCP GKE (Autopilot) | ✅ Validé | +| AWS EKS | ⚠️ Implémenté, non testé en production | +| On-premise / Minikube | ✅ Testé localement | + +# Disclaimer + +Ce chart Helm est fourni par Absyss SAS comme un **déploiement de référence** de Visual TOM sur Kubernetes. Il est conçu comme un **point de départ** qui doit être adapté par chaque client à son infrastructure, à ses exigences de sécurité et à ses contraintes opérationnelles (topologie réseau, gestion des secrets, classes de stockage, contrôleur Ingress, politiques RBAC, etc.). + +Le chart est distribué **tel quel**, sans garantie d'aucune sorte. Absyss SAS ne peut être tenu responsable des dommages résultant de son utilisation ou des adaptations effectuées par le client. + +Les contrats de support Visual TOM standard ne couvrent pas le chart Helm lui-même ni les adaptations Kubernetes côté client. Des jours de consulting peuvent être demandés pour accompagner le déploiement, la personnalisation ou la résolution de problèmes. + +# Prérequis + +## Tous les environnements +- **Visual TOM** ≥ 7.3.2c (versions inférieures non testées avec ce chart) +- **Kubernetes** ≥ 1.28 +- **Helm** ≥ 3.8 (requis pour l'installation depuis le registry OCI) +- **PostgreSQL 17** accessible depuis le cluster (VNet, VPC ou réseau local) +- Un **contrôleur Ingress** installé — **Traefik** est utilisé par défaut, nginx est également supporté +- **cert-manager** installé avec un `ClusterIssuer` configuré si vous utilisez Let's Encrypt (option TLS par défaut). L'installation et la configuration de cert-manager sont à la charge du client — le chart se contente de créer les ressources `Certificate`. Si vous fournissez vos propres certificats TLS (`tls.provider: secret`), cert-manager n'est pas nécessaire +- **ExternalDNS** (optionnel) — pour la gestion automatique des enregistrements DNS du service LoadBalancer. Sans ExternalDNS, les enregistrements DNS doivent être créés manuellement. Voir `vtom.serverService.hostname` dans les values +- Une **licence VTOM** valide et un accès à un registry d'images + +> **Accès réseau privé / VPN :** les ressources type WireGuard, Private Endpoint, Cloud SQL Auth Proxy, etc. ne font **pas** partie de ce chart. Elles sont à provisionner en amont via votre IaC (Terraform, Bicep, etc.). + +## Prérequis cloud-spécifiques + +### Azure (AKS) +- ACR (Azure Container Registry) avec les images VTOM/ITC/ITM/MFT chargées +- Azure Key Vault avec les secrets créés (voir section Azure ci-dessous) +- User-Assigned Managed Identity avec accès Key Vault (`Key Vault Secrets User`) +- External Secrets Operator installé dans le cluster + +### AWS (EKS) +- ECR ou autre registry avec les images chargées +- AWS Secrets Manager avec les secrets créés +- IAM Role avec accès Secrets Manager, associé au ServiceAccount via IRSA +- External Secrets Operator installé dans le cluster + +### GCP (GKE) +- Artifact Registry ou GCR avec les images chargées +- GCP Secret Manager avec les secrets créés +- GCP Service Account avec accès Secret Manager, lié via Workload Identity +- External Secrets Operator installé dans le cluster +- Cloud SQL Auth Proxy activé dans les valeurs (préconfiguré dans `values-gcp.yaml`) + +### On-premise +- Registry Docker local ou images chargées manuellement (`docker load`) +- PostgreSQL accessible depuis les pods +- Secrets Kubernetes créés manuellement (voir section on-premise ci-dessous) +- Une **implémentation LoadBalancer** telle que [MetalLB](https://metallb.universe.tf/) — requise pour qu'une IP soit assignée aux Services `vtom-server` et `mft-sftp`. Sans cela, les Services `type: LoadBalancer` restent indéfiniment en état ``. Sur les clusters bare-metal ou locaux (RKE2, kubeadm, Minikube), ceci n'est pas fourni par défaut + +# Produits + +Le chart déploie 4 produits Visual TOM, chacun activable indépendamment via son toggle `.enabled`. Tous se partagent les paramètres globaux (registry, namespace, base de données, exposition réseau, NetworkPolicy). + +## VTOM — Ordonnanceur + +Le cœur de Visual TOM. Trois composants déployés en pods distincts, partageant la même image. + +| Composant | Rôle | Service | PVC | Mémoire (limite) | +|---|---|---|---|---| +| `vtom-server` | Moteur d'ordonnancement | LoadBalancer (5 ports natifs VTOM) | 5 Gi | 1 Gi | +| `vtom-apiserver` | API REST + interface web | ClusterIP + Ingress HTTPS | 2 Gi | 1.5 Gi | +| `vtom-agent` | Exécution des jobs Kubernetes | (aucun) | 10 Gi | 256 Mi | + +**Paramètres typiques :** +- `vtom.image.tag` — version VTOM (ex. `7.3.2c`) +- `vtom.ingress.host` — FQDN apiserver, ex. `vtom.mycompany.com` +- `vtom.serverService.hostname` — FQDN client VTOM Desktop (géré par ExternalDNS) +- `vtom.serverService.loadBalancerIP` — IP statique pour survivre aux reprovisions du LB +- `vtom.timezone` — fuseau horaire partagé (défaut `Europe/Paris`) +- `vtom.{server,apiserver,agent}Resources` — CPU/mémoire par composant +- `vtom.{server,apiserver,agent}Pvc.size` — tailles de stockage + +**Licence :** `vtom.license.secretName` (défaut `vtom-license-secret`) — partagée avec ITC et ITM par défaut. + +**Base :** DB nommée `vtom`, secret `vtom-db-secret` (clés `TOM_SGBD_USER` + `TOM_SGBD_PASSWORD` — mot de passe **chiffré format VTOM**, cf. [Format des secrets](#format-des-secrets)). + +**Désactiver :** `vtom.enabled: false` (utile si vous déployez uniquement ITC/ITM/MFT contre un serveur VTOM externe). + +## ITC — Visual TOM User Portal + +Portail utilisateur web pour piloter VTOM (visualisation, supervision, drag & drop). + +| Composant | Rôle | Service | PVC | Mémoire (limite) | +|---|---|---|---|---| +| `itc` | Portail web utilisateur | ClusterIP + Ingress HTTPS | 2 Gi | 1 Gi | + +**Paramètres typiques :** +- `itc.image.tag` — version ITC (**requise** si `itc.enabled=true`) +- `itc.ingress.host` — FQDN ITC, ex. `vitc.mycompany.com` +- `itc.resources`, `itc.pvc.size` + +**Licence :** par défaut réutilise la licence VTOM (`itc.license.secretName: vtom-license-secret`). + +**Base :** DB nommée `ITCockpits`, secret `itc-db-secret` (clés `ITDB_USER` + `ITDB_PASSWORD` — mot de passe **en clair**). + +**Désactiver :** `itc.enabled: false`. + +## ITM — Visual IT Messenger + +Service de messagerie / notification (envoi de courriels, alertes intégrées au workflow VTOM). + +| Composant | Rôle | Service | PVC | Mémoire (limite) | +|---|---|---|---|---| +| `itm` | Messenger | ClusterIP + Ingress HTTPS | 2 Gi | 1 Gi | + +**Paramètres typiques :** +- `itm.image.tag` — version ITM (**requise** si `itm.enabled=true`) +- `itm.ingress.host` — FQDN ITM, ex. `vitm.mycompany.com` +- `itm.resources`, `itm.pvc.size` + +**Licence :** par défaut réutilise la licence VTOM (`itm.license.secretName: vtom-license-secret`). + +**Base :** DB nommée `ITMessenger`, secret `itm-db-secret` (clés `ITDB_USER` + `ITDB_PASSWORD` — mot de passe **en clair**). + +**Désactiver :** `itm.enabled: false`. + +## MFT — Visual TOM Managed File Transfer + +Transferts de fichiers managés : serveur SFTP entrant + connecteurs sortants vers backends externes (NFS, S3, Azure Blob, FTP, SFTP). **Pas de base de données ni de licence séparée.** + +| Composant | Rôle | Services | PVC | Mémoire (limite) | +|---|---|---|---|---| +| `vtom-mft` | Portail HTTPS + serveur SFTP | `mft` (ClusterIP) + `mft-sftp` (LoadBalancer) + Ingress HTTPS | 1 Gi | 1 Gi | + +**Ports exposés :** +- `30034` — portail HTTPS (TLS auto-signé côté pod) +- `30022` — SFTP (accès clients externes via LoadBalancer) + +**Paramètres typiques :** +- `mft.image.tag` — version MFT (**requise** si `mft.enabled=true`) +- `mft.ingress.host` — FQDN portail web, ex. `mft.mycompany.com` +- `mft.sftpService.hostname` — FQDN SFTP (géré par ExternalDNS) +- `mft.sftpService.loadBalancerIP` — IP statique du LB SFTP +- `mft.sftpService.loadBalancerSourceRanges` — **toujours renseigner en production** pour restreindre l'accès SFTP par IP +- `mft.externalEgress` — règles NetworkPolicy de sortie vers les backends de stockage (NFS, S3, FTP, SFTP) +- `mft.pvcSeed.enabled` — init container qui prépare la structure du PVC au premier démarrage + +**Désactiver :** `mft.enabled: false`. + +# Installation + +## Depuis le registry public OCI (recommandé) + +Le chart est publié en tant qu'artefact OCI sur GitHub Container Registry. Aucune authentification requise. + +**Étape 1 — Récupérer le chart en local** : +```bash +helm pull oci://ghcr.io/absysslab/visual-tom --version 0.1.0 --untar +``` +Cette commande télécharge le chart et le dépaquette dans un dossier `visual-tom/` contenant `Chart.yaml`, `values.yaml`, tous les `values-.yaml`, le `values-client-template.yaml` et les `templates/`. + +**Étape 2 — Préparer votre fichier de valeurs client** : +```bash +cp visual-tom/values-client-template.yaml values-monentreprise.yaml +# Éditer values-monentreprise.yaml et remplir les lignes marquées « # TODO » +``` + +**Étape 3 — Installer** : +```bash +helm install visual-tom ./visual-tom \ + -f visual-tom/values-azure.yaml \ + -f values-monentreprise.yaml \ + --namespace vtom --create-namespace +``` + +Remplacer `values-azure.yaml` par `values-aws.yaml`, `values-gcp.yaml` ou `values-onpremise.yaml` selon votre cible. + +> **Mises à jour** : pour passer à une version ultérieure (ex. 0.1.1), relancer l'étape 1 avec `--version 0.1.1`, vérifier les changements éventuels dans les `values-.yaml`, puis `helm upgrade visual-tom ./visual-tom -f ... -f values-monentreprise.yaml --namespace vtom`. + +## Depuis les sources + +```bash +git clone https://github.com/AbsyssLab/vtom-helm.git +cd vtom-helm + +helm install visual-tom ./charts/visual-tom \ + -f ./charts/visual-tom/values-azure.yaml \ + -f values-monentreprise.yaml \ + --namespace vtom --create-namespace +``` + +# Configuration + +## Superposition des fichiers de valeurs + +Helm fusionne les fichiers de valeurs dans l'ordre indiqué sur la ligne de commande. Chaque fichier suivant écrase les valeurs du précédent : + +``` +values.yaml (defaults internes, chargé automatiquement) + + +values-.yaml (remplace les defaults par les valeurs cloud-spécifiques) + + +values-monentreprise.yaml (remplace par VOS valeurs spécifiques) + = +configuration finale déployée +``` + +## Étapes + +1. **Copier** `values-client-template.yaml` → `values-monentreprise.yaml` +2. **Remplir** toutes les lignes marquées `# TODO` +3. **Ne pas modifier** `values.yaml` ni les fichiers `values-.yaml` + +## Exposition réseau + +Par défaut, **tout est privé en production**. Le chart impose un Load Balancer interne pour `vtom.serverService` (VTOM Desktop) et `mft.sftpService` (SFTP) via des annotations spécifiques à chaque cloud, déjà configurées dans les fichiers `values-.yaml`. + +| Composant | Défaut | Override (public, tests) | Configuré dans | +|---|---|---|---| +| PostgreSQL | Endpoint privé (Private Endpoint, Private IP, VPC peering) | FQDN public | `database.host` — ce chart | +| vtom-server (VTOM Desktop) | LB interne — **imposé par le chart** | LB public | `vtom.serverService.annotations` — ce chart | +| MFT SFTP | LB interne — **imposé par le chart** | LB public | `mft.sftpService.annotations` — ce chart | +| Interfaces web (Ingress) | LB interne — **recommandé côté client** | LB public | Paramètres du contrôleur Ingress — **hors du chart** | + +**Annotations LB interne par cloud** (déjà configurées dans `values-.yaml`) : + +| Cloud | Annotations | +|---|---| +| Azure | `service.beta.kubernetes.io/azure-load-balancer-internal: "true"` | +| AWS | `aws-load-balancer-scheme: "internal"` (+ `aws-load-balancer-type: "external"`, `nlb-target-type: "ip"`) | +| GCP | `networking.gke.io/load-balancer-type: "Internal"` | +| On-premise | aucune — nécessite une implémentation LoadBalancer (ex. [MetalLB](https://metallb.universe.tf/)) | + +**Exposer publiquement (tests uniquement)** — surcharger les annotations dans `values-monentreprise.yaml` : +```yaml +vtom: + serverService: + annotations: {} # Désactive le LB interne + loadBalancerSourceRanges: + - "203.0.113.0/24" # Restreindre aux IPs autorisées +``` + +**Restreindre l'accès au LB interne par IP** (production) : +```yaml +vtom: + serverService: + loadBalancerSourceRanges: + - "10.0.0.0/8" # Réseau interne (VNet/VPC + VPN clients) +``` + +## Format des secrets + +Les conventions suivantes s'appliquent à **toutes les infrastructures** (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager, secrets Kubernetes natifs) : + +| Produit | Utilisateur DB | Mot de passe DB | +|---|---|---| +| **VTOM** | Texte brut | **Chiffré format VTOM** (bcrypt Absyss) — utiliser l'outil de chiffrement fourni par Absyss | +| **ITC** | Texte brut | **En clair** (ITC ne supporte pas le chiffrement VTOM) | +| **ITM** | Texte brut | **En clair** (ITM ne supporte pas le chiffrement VTOM) | + +> **Important :** ne **jamais** stocker le mot de passe VTOM en clair. Le format attendu est le hash bcrypt généré par l'outil Absyss. À l'inverse, les mots de passe ITC et ITM doivent rester en clair — toute tentative de chiffrement entraînera un échec de connexion. + +## Configuration par environnement + +### Azure (AKS) + +**Valeurs obligatoires :** + +| Paramètre | Description | Exemple | +|---|---|---| +| `global.imageRegistry` | Nom de l'ACR | `monacr.azurecr.io` | +| `vtom.image.tag` | Version VTOM | `7.3.2c` | +| `itc.image.tag` | Version ITC | `7.3.2c` | +| `itm.image.tag` | Version ITM | `7.3.2c` | +| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | +| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | +| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | +| `database.host` | FQDN PostgreSQL | `vtom-pg.postgres.database.azure.com` | +| `secrets.azure.keyVaultUrl` | URL du Key Vault | `https://mon-kv.vault.azure.net` | +| `secrets.azure.tenantId` | ID du tenant Azure AD | `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | +| `serviceAccount.azure.clientId` | Client ID de la Managed Identity | `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy` | + +**Secrets à créer dans Azure Key Vault :** + +| Nom du secret | Contenu | Format | +|---|---|---| +| `vtom-db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | +| `vtom-db-password` | Mot de passe VTOM pour PostgreSQL | **Chiffré format VTOM** (bcrypt Absyss) | +| `vtom-license-register` | Contenu du fichier `license.register` | Texte brut | +| `itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | +| `itc-db-password` | Mot de passe ITC pour PostgreSQL | **En clair** | +| `itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | +| `itm-db-password` | Mot de passe ITM pour PostgreSQL | **En clair** | + +> **PostgreSQL — privé vs public :** sur Azure, utilisez de préférence un **Private Endpoint** sur le serveur PostgreSQL flexible (FQDN `.private.postgres.database.azure.com`). Le FQDN public Azure (`.postgres.database.azure.com`) ne doit être utilisé qu'en test, avec firewall PostgreSQL restreint à votre VNet. + +### AWS (EKS) + +**Valeurs obligatoires :** + +| Paramètre | Description | Exemple | +|---|---|---| +| `global.imageRegistry` | Registry ECR | `123456789.dkr.ecr.eu-west-1.amazonaws.com` | +| `vtom.image.tag` | Version VTOM | `7.3.2c` | +| `itc.image.tag` | Version ITC | `7.3.2c` | +| `itm.image.tag` | Version ITM | `7.3.2c` | +| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | +| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | +| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | +| `database.host` | Endpoint RDS | `vtom.xxxx.eu-west-1.rds.amazonaws.com` | +| `secrets.aws.region` | Région AWS | `eu-west-1` | +| `serviceAccount.aws.roleArn` | ARN du rôle IAM | `arn:aws:iam::123456789012:role/vtom-role` | + +**Secrets à créer dans AWS Secrets Manager :** + +| Nom du secret | Contenu | Format | +|---|---|---| +| `vtom/db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | +| `vtom/db-password` | Mot de passe VTOM | **Chiffré format VTOM** | +| `vtom/license-register` | Fichier `license.register` | Texte brut | +| `vtom/itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | +| `vtom/itc-db-password` | Mot de passe ITC | **En clair** | +| `vtom/itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | +| `vtom/itm-db-password` | Mot de passe ITM | **En clair** | + +### GCP (GKE) + +**Valeurs obligatoires :** + +| Paramètre | Description | Exemple | +|---|---|---| +| `global.imageRegistry` | Artifact Registry | `europe-west1-docker.pkg.dev/mon-projet/vtom` | +| `vtom.image.tag` | Version VTOM | `7.3.2c` | +| `itc.image.tag` | Version ITC | `7.3.2c` | +| `itm.image.tag` | Version ITM | `7.3.2c` | +| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | +| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | +| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | +| `dbProxy.cloudsqlProxy.instanceConnectionName` | Instance Cloud SQL | `mon-projet:europe-west1:vtom-postgres` | +| `secrets.gcp.projectId` | ID du projet GCP | `mon-projet-gcp` | +| `serviceAccount.gcp.serviceAccount` | GSA liée au KSA | `vtom@mon-projet.iam.gserviceaccount.com` | + +**Secrets à créer dans GCP Secret Manager :** + +| Nom du secret | Contenu | Format | +|---|---|---| +| `vtom-db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | +| `vtom-db-password` | Mot de passe VTOM | **Chiffré format VTOM** | +| `vtom-license-register` | Fichier `license.register` | Texte brut | +| `itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | +| `itc-db-password` | Mot de passe ITC | **En clair** | +| `itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | +| `itm-db-password` | Mot de passe ITM | **En clair** | + +### On-premise / RKE2 / Minikube + +**Valeurs obligatoires :** + +| Paramètre | Description | Exemple | +|---|---|---| +| `global.imageRegistry` | Registry local | `registry.monentreprise.com` | +| `vtom.image.tag` | Version VTOM | `7.3.2c` | +| `itc.image.tag` | Version ITC | `7.3.2c` | +| `itm.image.tag` | Version ITM | `7.3.2c` | +| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.local` | +| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.local` | +| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.local` | +| `database.host` | Hostname/IP PostgreSQL | `192.168.1.50` | + +**Secrets Kubernetes à créer manuellement avant le déploiement :** + +```bash +kubectl create namespace vtom + +# Utilisateur + mot de passe VTOM (mot de passe CHIFFRÉ au format VTOM — bcrypt Absyss) +kubectl create secret generic vtom-db-secret \ + --from-literal=TOM_SGBD_USER='' \ + --from-literal=TOM_SGBD_PASSWORD='' \ + -n vtom + +# Licence VTOM/ITC/ITM (fichier fourni par Absyss) +kubectl create secret generic vtom-license-secret \ + --from-file=license.register=/chemin/vers/license.register \ + -n vtom + +# Utilisateur + mot de passe ITC — EN CLAIR +kubectl create secret generic itc-db-secret \ + --from-literal=ITDB_USER='' \ + --from-literal=ITDB_PASSWORD='' \ + -n vtom + +# Utilisateur + mot de passe ITM — EN CLAIR +kubectl create secret generic itm-db-secret \ + --from-literal=ITDB_USER='' \ + --from-literal=ITDB_PASSWORD='' \ + -n vtom +``` + +## NetworkPolicy — Health checks Load Balancer + +Pour que les Load Balancers cloud puissent vérifier la santé des pods (probes), les CIDRs d'origine des probes doivent être explicitement autorisés dans la NetworkPolicy. Configurez `networkPolicy.lbHealthCheckCidrs` selon votre cloud : + +| Cloud | Valeur recommandée | +|---|---| +| Azure | `["168.63.129.16/32"]` | +| AWS | CIDR du VPC (ex. `["172.31.0.0/16"]`) — ne **pas** utiliser `["0.0.0.0/0"]` en production | +| GCP | `["130.211.0.0/22", "35.191.0.0/16"]` (Internal LB utilise les deux ranges) | +| On-premise | `[]` (pas de probe cloud) | + +Les fichiers `values-.yaml` fournissent déjà la bonne valeur par défaut. + +# Architecture + +![Architecture VTOM sur Kubernetes](architecture.png) + +# Mise à jour + +```bash +# Via OCI +helm upgrade visual-tom oci://ghcr.io/absysslab/visual-tom \ + --version 0.1.1 \ + -f values-azure.yaml \ + -f values-monentreprise.yaml \ + --namespace vtom + +# Depuis les sources +helm upgrade visual-tom ./charts/visual-tom \ + -f ./charts/visual-tom/values-azure.yaml \ + -f values-monentreprise.yaml \ + --namespace vtom +``` + +# Désinstallation + +```bash +helm uninstall visual-tom -n vtom +``` + +Par défaut, **les PersistentVolumeClaims (PVC) et les PersistentVolumes (PV) sous-jacents sont conservés** (`reclaimPolicy: Retain`). Cela protège vos données (clés de chiffrement, logs, journaux, configuration) contre une suppression accidentelle. + +> ⚠️ **AVERTISSEMENT — Perte de données irréversible** +> +> Les commandes ci-dessous suppriment définitivement **toutes les données VTOM, ITC, ITM et MFT**. Sur Azure / AWS / GCP, le disque cloud sous-jacent est également supprimé. **Aucune restauration n'est possible sans sauvegarde préalable**. +> +> N'exécuter qu'après avoir : +> - Effectué un dump complet de PostgreSQL +> - Sauvegardé les fichiers de configuration et journaux des PVC +> - Confirmé que ces données ne sont plus nécessaires + +```bash +# 1. Supprimer les PVC (libère les PV qui passent en état "Released") +kubectl delete pvc --all -n vtom + +# 2. Supprimer les PV libérés (perte définitive des disques sous-jacents) +kubectl get pv | grep "vtom/" | awk '{print $1}' | xargs -r kubectl delete pv + +# 3. (Optionnel) Supprimer le namespace +kubectl delete namespace vtom +``` + +# Vérification du déploiement + +```bash +kubectl get pods -n vtom +kubectl get ingress -n vtom +kubectl get svc -n vtom +helm status visual-tom -n vtom +``` + +# Résolution de problèmes + +**Les pods restent en `Pending` :** +```bash +kubectl describe pod -n vtom +# Vérifier les events — souvent un problème de PVC ou de ressources insuffisantes +``` + +**Les pods restent en `Init:0/1` ou `Init:Error` :** +```bash +kubectl logs -n vtom -c wait-for-db +# Le proxy DB ne démarre pas ou la DB est inaccessible +``` + +**Les secrets ESO ne se synchronisent pas :** +```bash +kubectl get externalsecret -n vtom +kubectl describe externalsecret vtom-db-secret -n vtom +# Vérifier les permissions de la Managed Identity / IAM Role / GSA sur le coffre de secrets +``` + +**Le certificat TLS n'est pas émis :** +```bash +kubectl get certificate -n vtom +kubectl describe certificate vtom-tls-cert -n vtom +# Vérifier que le ClusterIssuer est prêt et que le domaine est accessible depuis internet +``` + +**Le Load Balancer reste `` ou les probes échouent :** +```bash +kubectl describe svc vtom-server -n vtom +# Côté NetworkPolicy : vérifier networkPolicy.lbHealthCheckCidrs (cf. section dédiée) +# Côté cloud : vérifier annotations et quotas LB +``` + +# Licence + +Ce projet est sous licence Apache 2.0. Voir le fichier [LICENSE](LICENSE) pour plus de détails. diff --git a/charts/visual-tom/README.md b/charts/visual-tom/README.md new file mode 100644 index 0000000..1947a66 --- /dev/null +++ b/charts/visual-tom/README.md @@ -0,0 +1,517 @@ +# Visual TOM — Kubernetes Helm Chart +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)  +[![fr](https://img.shields.io/badge/lang-fr-yellow.svg)](README-fr.md) + +This repository provides a Helm chart to deploy **Visual TOM (Absyss)** and its related products on Kubernetes: + +- **VTOM** — Scheduler (core) +- **ITC** — Visual TOM User Portal +- **ITM** — Visual IT Messenger +- **MFT** — Visual TOM Managed File Transfer + +Validated targets: + +| Environment | Status | +|---|---| +| Azure AKS | ✅ Validated | +| GCP GKE (Autopilot) | ✅ Validated | +| AWS EKS | ⚠️ Implemented, not tested in production | +| On-premise / Minikube | ✅ Tested locally | + +# Disclaimer + +This Helm chart is provided by Absyss SAS as a **reference deployment** of Visual TOM on Kubernetes. It is designed as a **starting point** that must be adapted by each client to match their specific infrastructure, security requirements and operational constraints (network topology, secrets management, storage classes, ingress controller, RBAC policies, etc.). + +The chart is distributed **as-is**, without warranty of any kind. Absyss SAS is not liable for damages resulting from its use or from client-side adaptations. + +Standard Visual TOM support contracts do not cover the Helm chart itself or client-side Kubernetes adaptations. Consulting days can be requested to assist with deployment, customization or troubleshooting. + +# Prerequisites + +## All environments +- **Visual TOM** ≥ 7.3.2c (earlier versions are not tested with this chart) +- **Kubernetes** ≥ 1.28 +- **Helm** ≥ 3.8 (required to install from the OCI registry) +- **PostgreSQL 17** reachable from the cluster (VNet, VPC or local network) +- An **Ingress controller** installed — **Traefik** is used by default, nginx is also supported +- **cert-manager** installed with a `ClusterIssuer` configured if you use Let's Encrypt (default TLS option). Installing and configuring cert-manager is the client's responsibility — the chart only creates the `Certificate` resources. If you provide your own TLS certificates (`tls.provider: secret`), cert-manager is not required +- **ExternalDNS** (optional) — for automatic DNS record management of the LoadBalancer service. Without ExternalDNS, DNS records must be created manually. See `vtom.serverService.hostname` in the values +- A valid **VTOM license** and access to an image registry + +> **Private network access / VPN:** resources such as WireGuard, Private Endpoints, Cloud SQL Auth Proxy, etc. are **not** part of this chart. They must be provisioned upstream via your IaC (Terraform, Bicep, etc.). + +## Cloud-specific prerequisites + +### Azure (AKS) +- ACR (Azure Container Registry) with the VTOM/ITC/ITM/MFT images loaded +- Azure Key Vault with the secrets created (see Azure section below) +- User-Assigned Managed Identity with Key Vault access (`Key Vault Secrets User`) +- External Secrets Operator installed in the cluster + +### AWS (EKS) +- ECR or another registry with the images loaded +- AWS Secrets Manager with the secrets created +- IAM Role with Secrets Manager access, associated with the ServiceAccount via IRSA +- External Secrets Operator installed in the cluster + +### GCP (GKE) +- Artifact Registry or GCR with the images loaded +- GCP Secret Manager with the secrets created +- GCP Service Account with Secret Manager access, linked via Workload Identity +- External Secrets Operator installed in the cluster +- Cloud SQL Auth Proxy enabled in the values (preconfigured in `values-gcp.yaml`) + +### On-premise +- Local Docker registry or images loaded manually (`docker load`) +- PostgreSQL reachable from the pods +- Kubernetes secrets created manually (see on-premise section below) +- A **LoadBalancer implementation** such as [MetalLB](https://metallb.universe.tf/) — required to assign an IP to `vtom-server` and `mft-sftp` Services. Without it, `type: LoadBalancer` Services remain in `` state indefinitely. On bare-metal or local clusters (RKE2, kubeadm, Minikube), this is not provided by default + +# Products + +The chart deploys 4 Visual TOM products, each independently toggleable via its `.enabled` flag. They all share global settings (registry, namespace, database, network exposure, NetworkPolicy). + +## VTOM — Scheduler + +The core of Visual TOM. Three components deployed as separate pods, sharing the same image. + +| Component | Role | Service | PVC | Memory (limit) | +|---|---|---|---|---| +| `vtom-server` | Scheduling engine | LoadBalancer (5 native VTOM ports) | 5 Gi | 1 Gi | +| `vtom-apiserver` | REST API + web interface | ClusterIP + HTTPS Ingress | 2 Gi | 1.5 Gi | +| `vtom-agent` | Kubernetes job executor | (none) | 10 Gi | 256 Mi | + +**Typical parameters:** +- `vtom.image.tag` — VTOM version (e.g. `7.3.2c`) +- `vtom.ingress.host` — apiserver FQDN, e.g. `vtom.mycompany.com` +- `vtom.serverService.hostname` — VTOM Desktop client FQDN (managed by ExternalDNS) +- `vtom.serverService.loadBalancerIP` — static IP to survive LB reprovisioning +- `vtom.timezone` — shared timezone (default `Europe/Paris`) +- `vtom.{server,apiserver,agent}Resources` — CPU/memory per component +- `vtom.{server,apiserver,agent}Pvc.size` — storage sizes + +**License:** `vtom.license.secretName` (default `vtom-license-secret`) — shared with ITC and ITM by default. + +**Database:** DB named `vtom`, secret `vtom-db-secret` (keys `TOM_SGBD_USER` + `TOM_SGBD_PASSWORD` — password **VTOM-encrypted**, see [Secret formats](#secret-formats)). + +**Disable:** `vtom.enabled: false` (useful if you only deploy ITC/ITM/MFT against an external VTOM server). + +## ITC — Visual TOM User Portal + +Web user portal to operate VTOM (visualization, monitoring, drag & drop). + +| Component | Role | Service | PVC | Memory (limit) | +|---|---|---|---|---| +| `itc` | Web user portal | ClusterIP + HTTPS Ingress | 2 Gi | 1 Gi | + +**Typical parameters:** +- `itc.image.tag` — ITC version (**required** if `itc.enabled=true`) +- `itc.ingress.host` — ITC FQDN, e.g. `vitc.mycompany.com` +- `itc.resources`, `itc.pvc.size` + +**License:** by default reuses the VTOM license (`itc.license.secretName: vtom-license-secret`). + +**Database:** DB named `ITCockpits`, secret `itc-db-secret` (keys `ITDB_USER` + `ITDB_PASSWORD` — password **plain text**). + +**Disable:** `itc.enabled: false`. + +## ITM — Visual IT Messenger + +Messaging / notification service (email sending, alerts integrated into the VTOM workflow). + +| Component | Role | Service | PVC | Memory (limit) | +|---|---|---|---|---| +| `itm` | Messenger | ClusterIP + HTTPS Ingress | 2 Gi | 1 Gi | + +**Typical parameters:** +- `itm.image.tag` — ITM version (**required** if `itm.enabled=true`) +- `itm.ingress.host` — ITM FQDN, e.g. `vitm.mycompany.com` +- `itm.resources`, `itm.pvc.size` + +**License:** by default reuses the VTOM license (`itm.license.secretName: vtom-license-secret`). + +**Database:** DB named `ITMessenger`, secret `itm-db-secret` (keys `ITDB_USER` + `ITDB_PASSWORD` — password **plain text**). + +**Disable:** `itm.enabled: false`. + +## MFT — Visual TOM Managed File Transfer + +Managed file transfers: inbound SFTP server + outbound connectors to external backends (NFS, S3, Azure Blob, FTP, SFTP). **No database, no separate license.** + +| Component | Role | Services | PVC | Memory (limit) | +|---|---|---|---|---| +| `vtom-mft` | HTTPS portal + SFTP server | `mft` (ClusterIP) + `mft-sftp` (LoadBalancer) + HTTPS Ingress | 1 Gi | 1 Gi | + +**Exposed ports:** +- `30034` — HTTPS portal (self-signed TLS served by the pod) +- `30022` — SFTP (external client access via LoadBalancer) + +**Typical parameters:** +- `mft.image.tag` — MFT version (**required** if `mft.enabled=true`) +- `mft.ingress.host` — web portal FQDN, e.g. `mft.mycompany.com` +- `mft.sftpService.hostname` — SFTP FQDN (managed by ExternalDNS) +- `mft.sftpService.loadBalancerIP` — static IP of the SFTP LB +- `mft.sftpService.loadBalancerSourceRanges` — **always set in production** to restrict SFTP access by IP +- `mft.externalEgress` — egress NetworkPolicy rules to storage backends (NFS, S3, FTP, SFTP) +- `mft.pvcSeed.enabled` — init container that prepares the PVC structure on first startup + +**Disable:** `mft.enabled: false`. + +# Installation + +## From the public OCI registry (recommended) + +The chart is published as an OCI artifact on GitHub Container Registry. No authentication required. + +**Step 1 — Pull the chart locally**: +```bash +helm pull oci://ghcr.io/absysslab/visual-tom --version 0.1.0 --untar +``` +This downloads the chart and extracts it into a `visual-tom/` directory containing `Chart.yaml`, `values.yaml`, all `values-.yaml`, the `values-client-template.yaml` and the `templates/`. + +**Step 2 — Prepare your client values file**: +```bash +cp visual-tom/values-client-template.yaml values-mycompany.yaml +# Edit values-mycompany.yaml and fill in the lines marked "# TODO" +``` + +**Step 3 — Install**: +```bash +helm install visual-tom ./visual-tom \ + -f visual-tom/values-azure.yaml \ + -f values-mycompany.yaml \ + --namespace vtom --create-namespace +``` + +Replace `values-azure.yaml` with `values-aws.yaml`, `values-gcp.yaml` or `values-onpremise.yaml` according to your target. + +> **Upgrades**: to move to a later version (e.g. 0.1.1), re-run step 1 with `--version 0.1.1`, review any changes in the `values-.yaml`, then `helm upgrade visual-tom ./visual-tom -f ... -f values-mycompany.yaml --namespace vtom`. + +## From sources + +```bash +git clone https://github.com/AbsyssLab/vtom-helm.git +cd vtom-helm + +helm install visual-tom ./charts/visual-tom \ + -f ./charts/visual-tom/values-azure.yaml \ + -f values-mycompany.yaml \ + --namespace vtom --create-namespace +``` + +# Configuration + +## Values files layering + +Helm merges values files in the order they appear on the command line. Each subsequent file overrides the previous one: + +``` +values.yaml (internal defaults, loaded automatically) + + +values-.yaml (overrides defaults with cloud-specific values) + + +values-mycompany.yaml (overrides with YOUR specific values) + = +final deployed configuration +``` + +## Steps + +1. **Copy** `values-client-template.yaml` → `values-mycompany.yaml` +2. **Fill in** all lines marked `# TODO` +3. **Do not modify** `values.yaml` or any `values-.yaml` file + +## Network exposure + +By default, **everything is private in production**. The chart enforces an internal Load Balancer for `vtom.serverService` (VTOM Desktop) and `mft.sftpService` (SFTP) via cloud-specific annotations, already configured in the `values-.yaml` files. + +| Component | Default | Override (public, tests) | Configured in | +|---|---|---|---| +| PostgreSQL | Private endpoint (Private Endpoint, Private IP, VPC peering) | Public FQDN | `database.host` — this chart | +| vtom-server (VTOM Desktop) | Internal LB — **enforced by the chart** | Public LB | `vtom.serverService.annotations` — this chart | +| MFT SFTP | Internal LB — **enforced by the chart** | Public LB | `mft.sftpService.annotations` — this chart | +| Web interfaces (Ingress) | Internal LB — **recommended on the client side** | Public LB | Ingress controller settings — **out of scope of the chart** | + +**Internal LB annotations per cloud** (already configured in `values-.yaml`): + +| Cloud | Annotations | +|---|---| +| Azure | `service.beta.kubernetes.io/azure-load-balancer-internal: "true"` | +| AWS | `aws-load-balancer-scheme: "internal"` (+ `aws-load-balancer-type: "external"`, `nlb-target-type: "ip"`) | +| GCP | `networking.gke.io/load-balancer-type: "Internal"` | +| On-premise | none — requires a LoadBalancer implementation (e.g. [MetalLB](https://metallb.universe.tf/)) | + +**Expose publicly (tests only)** — override the annotations in `values-mycompany.yaml`: +```yaml +vtom: + serverService: + annotations: {} # Disables the internal LB + loadBalancerSourceRanges: + - "203.0.113.0/24" # Restrict to authorized IPs +``` + +**Restrict access to the internal LB by IP** (production): +```yaml +vtom: + serverService: + loadBalancerSourceRanges: + - "10.0.0.0/8" # Internal network (VNet/VPC + client VPN) +``` + +## Secret formats + +The following conventions apply to **all infrastructures** (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager, native Kubernetes secrets): + +| Product | DB user | DB password | +|---|---|---| +| **VTOM** | Plain text | **VTOM-encrypted** (Absyss bcrypt) — use the encryption tool provided by Absyss | +| **ITC** | Plain text | **Plain text** (ITC does not support VTOM encryption) | +| **ITM** | Plain text | **Plain text** (ITM does not support VTOM encryption) | + +> **Important:** never store the VTOM password in plain text. The expected format is the bcrypt hash generated by the Absyss tool. Conversely, ITC and ITM passwords must remain plain text — any encryption attempt will cause connection failures. + +## Configuration per environment + +### Azure (AKS) + +**Required values:** + +| Parameter | Description | Example | +|---|---|---| +| `global.imageRegistry` | ACR name | `myacr.azurecr.io` | +| `vtom.image.tag` | VTOM version | `7.3.2c` | +| `itc.image.tag` | ITC version | `7.3.2c` | +| `itm.image.tag` | ITM version | `7.3.2c` | +| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | +| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | +| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | +| `database.host` | PostgreSQL FQDN | `vtom-pg.postgres.database.azure.com` | +| `secrets.azure.keyVaultUrl` | Key Vault URL | `https://my-kv.vault.azure.net` | +| `secrets.azure.tenantId` | Azure AD tenant ID | `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | +| `serviceAccount.azure.clientId` | Managed Identity client ID | `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy` | + +**Secrets to create in Azure Key Vault:** + +| Secret name | Content | Format | +|---|---|---| +| `vtom-db-user` | PostgreSQL user for VTOM | Plain text | +| `vtom-db-password` | VTOM password for PostgreSQL | **VTOM-encrypted** (Absyss bcrypt) | +| `vtom-license-register` | Content of the `license.register` file | Plain text | +| `itc-db-user` | PostgreSQL user for ITC | Plain text | +| `itc-db-password` | ITC password for PostgreSQL | **Plain text** | +| `itm-db-user` | PostgreSQL user for ITM | Plain text | +| `itm-db-password` | ITM password for PostgreSQL | **Plain text** | + +> **PostgreSQL — private vs public:** on Azure, prefer a **Private Endpoint** on the PostgreSQL Flexible Server (FQDN `.private.postgres.database.azure.com`). The Azure public FQDN (`.postgres.database.azure.com`) should only be used in test, with the PostgreSQL firewall restricted to your VNet. + +### AWS (EKS) + +**Required values:** + +| Parameter | Description | Example | +|---|---|---| +| `global.imageRegistry` | ECR registry | `123456789.dkr.ecr.eu-west-1.amazonaws.com` | +| `vtom.image.tag` | VTOM version | `7.3.2c` | +| `itc.image.tag` | ITC version | `7.3.2c` | +| `itm.image.tag` | ITM version | `7.3.2c` | +| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | +| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | +| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | +| `database.host` | RDS endpoint | `vtom.xxxx.eu-west-1.rds.amazonaws.com` | +| `secrets.aws.region` | AWS region | `eu-west-1` | +| `serviceAccount.aws.roleArn` | IAM Role ARN | `arn:aws:iam::123456789012:role/vtom-role` | + +**Secrets to create in AWS Secrets Manager:** + +| Secret name | Content | Format | +|---|---|---| +| `vtom/db-user` | PostgreSQL user for VTOM | Plain text | +| `vtom/db-password` | VTOM password | **VTOM-encrypted** | +| `vtom/license-register` | `license.register` file | Plain text | +| `vtom/itc-db-user` | PostgreSQL user for ITC | Plain text | +| `vtom/itc-db-password` | ITC password | **Plain text** | +| `vtom/itm-db-user` | PostgreSQL user for ITM | Plain text | +| `vtom/itm-db-password` | ITM password | **Plain text** | + +### GCP (GKE) + +**Required values:** + +| Parameter | Description | Example | +|---|---|---| +| `global.imageRegistry` | Artifact Registry | `europe-west1-docker.pkg.dev/my-project/vtom` | +| `vtom.image.tag` | VTOM version | `7.3.2c` | +| `itc.image.tag` | ITC version | `7.3.2c` | +| `itm.image.tag` | ITM version | `7.3.2c` | +| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | +| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | +| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | +| `dbProxy.cloudsqlProxy.instanceConnectionName` | Cloud SQL instance | `my-project:europe-west1:vtom-postgres` | +| `secrets.gcp.projectId` | GCP project ID | `my-gcp-project` | +| `serviceAccount.gcp.serviceAccount` | GSA linked to the KSA | `vtom@my-project.iam.gserviceaccount.com` | + +**Secrets to create in GCP Secret Manager:** + +| Secret name | Content | Format | +|---|---|---| +| `vtom-db-user` | PostgreSQL user for VTOM | Plain text | +| `vtom-db-password` | VTOM password | **VTOM-encrypted** | +| `vtom-license-register` | `license.register` file | Plain text | +| `itc-db-user` | PostgreSQL user for ITC | Plain text | +| `itc-db-password` | ITC password | **Plain text** | +| `itm-db-user` | PostgreSQL user for ITM | Plain text | +| `itm-db-password` | ITM password | **Plain text** | + +### On-premise / RKE2 / Minikube + +**Required values:** + +| Parameter | Description | Example | +|---|---|---| +| `global.imageRegistry` | Local registry | `registry.mycompany.com` | +| `vtom.image.tag` | VTOM version | `7.3.2c` | +| `itc.image.tag` | ITC version | `7.3.2c` | +| `itm.image.tag` | ITM version | `7.3.2c` | +| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.local` | +| `itc.ingress.host` | ITC domain | `vitc.mycompany.local` | +| `itm.ingress.host` | ITM domain | `vitm.mycompany.local` | +| `database.host` | PostgreSQL hostname/IP | `192.168.1.50` | + +**Kubernetes secrets to create manually before deployment:** + +```bash +kubectl create namespace vtom + +# VTOM user + password (password VTOM-ENCRYPTED — Absyss bcrypt) +kubectl create secret generic vtom-db-secret \ + --from-literal=TOM_SGBD_USER='' \ + --from-literal=TOM_SGBD_PASSWORD='' \ + -n vtom + +# VTOM/ITC/ITM license (file provided by Absyss) +kubectl create secret generic vtom-license-secret \ + --from-file=license.register=/path/to/license.register \ + -n vtom + +# ITC user + password — PLAIN TEXT +kubectl create secret generic itc-db-secret \ + --from-literal=ITDB_USER='' \ + --from-literal=ITDB_PASSWORD='' \ + -n vtom + +# ITM user + password — PLAIN TEXT +kubectl create secret generic itm-db-secret \ + --from-literal=ITDB_USER='' \ + --from-literal=ITDB_PASSWORD='' \ + -n vtom +``` + +## NetworkPolicy — Load Balancer health checks + +For cloud Load Balancers to be able to probe pod health, the source CIDRs of the probes must be explicitly allowed in the NetworkPolicy. Configure `networkPolicy.lbHealthCheckCidrs` according to your cloud: + +| Cloud | Recommended value | +|---|---| +| Azure | `["168.63.129.16/32"]` | +| AWS | VPC CIDR (e.g. `["172.31.0.0/16"]`) — do **not** use `["0.0.0.0/0"]` in production | +| GCP | `["130.211.0.0/22", "35.191.0.0/16"]` (Internal LB uses both ranges) | +| On-premise | `[]` (no cloud probe) | + +The `values-.yaml` files already provide the correct default value. + +# Architecture + +![VTOM on Kubernetes architecture](architecture.png) + +# Upgrade + +```bash +# Via OCI +helm upgrade visual-tom oci://ghcr.io/absysslab/visual-tom \ + --version 0.1.1 \ + -f values-azure.yaml \ + -f values-mycompany.yaml \ + --namespace vtom + +# From sources +helm upgrade visual-tom ./charts/visual-tom \ + -f ./charts/visual-tom/values-azure.yaml \ + -f values-mycompany.yaml \ + --namespace vtom +``` + +# Uninstallation + +```bash +helm uninstall visual-tom -n vtom +``` + +By default, **PersistentVolumeClaims (PVCs) and the underlying PersistentVolumes (PVs) are retained** (`reclaimPolicy: Retain`). This protects your data (encryption keys, application logs, audit logs, configuration) against accidental deletion. + +> ⚠️ **WARNING — Irreversible data loss** +> +> The commands below permanently delete **all VTOM, ITC, ITM and MFT data**. On Azure / AWS / GCP, the underlying cloud disk is also deleted. **No restoration is possible without a prior backup**. +> +> Only run after you have: +> - Taken a complete PostgreSQL dump +> - Backed up the configuration files and logs from the PVCs +> - Confirmed that this data is no longer needed + +```bash +# 1. Delete the PVCs (releases the PVs, which transition to "Released" state) +kubectl delete pvc --all -n vtom + +# 2. Delete the released PVs (permanent loss of the underlying disks) +kubectl get pv | grep "vtom/" | awk '{print $1}' | xargs -r kubectl delete pv + +# 3. (Optional) Delete the namespace +kubectl delete namespace vtom +``` + +# Verifying the deployment + +```bash +kubectl get pods -n vtom +kubectl get ingress -n vtom +kubectl get svc -n vtom +helm status visual-tom -n vtom +``` + +# Troubleshooting + +**Pods stay in `Pending`:** +```bash +kubectl describe pod -n vtom +# Check the events — typically a PVC issue or insufficient resources +``` + +**Pods stay in `Init:0/1` or `Init:Error`:** +```bash +kubectl logs -n vtom -c wait-for-db +# The DB proxy is not starting or the DB is unreachable +``` + +**ESO secrets are not syncing:** +```bash +kubectl get externalsecret -n vtom +kubectl describe externalsecret vtom-db-secret -n vtom +# Check the permissions of the Managed Identity / IAM Role / GSA on the secret store +``` + +**The TLS certificate is not being issued:** +```bash +kubectl get certificate -n vtom +kubectl describe certificate vtom-tls-cert -n vtom +# Check that the ClusterIssuer is ready and the domain is reachable from the internet +``` + +**The Load Balancer stays `` or probes are failing:** +```bash +kubectl describe svc vtom-server -n vtom +# NetworkPolicy side: check networkPolicy.lbHealthCheckCidrs (see dedicated section) +# Cloud side: check annotations and LB quotas +``` + +# License + +This project is licensed under the Apache 2.0 License — see the [LICENSE](LICENSE) file for details. diff --git a/charts/visual-tom/templates/common/networkpolicy.yaml b/charts/visual-tom/templates/common/networkpolicy.yaml index c0d41d1..1b7c0e6 100644 --- a/charts/visual-tom/templates/common/networkpolicy.yaml +++ b/charts/visual-tom/templates/common/networkpolicy.yaml @@ -99,13 +99,13 @@ spec: - port: {{ .Values.vtom.ports.svtnotifier }} protocol: TCP -{{- if .Values.vtom.apiserverExternalEgress.port }} +{{- if .Values.vtom.apiserverExternalEgress }} --- -# vtom-apiserver sends outbound traffic on dedicated external port +# vtom-apiserver outbound rules to external endpoints apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: allow-egress-apiserver-external-port + name: allow-egress-apiserver-external namespace: {{ include "vtom.namespace" . }} labels: {{- include "vtom.labels" . | nindent 4 }} @@ -116,12 +116,14 @@ spec: policyTypes: - Egress egress: + {{- range .Values.vtom.apiserverExternalEgress }} - to: - ipBlock: - cidr: {{ .Values.vtom.apiserverExternalEgress.cidr }} + cidr: {{ .cidr | quote }} ports: - - port: {{ .Values.vtom.apiserverExternalEgress.port }} - protocol: TCP + - port: {{ .port }} + protocol: {{ .protocol | default "TCP" }} + {{- end }} {{- end }} --- diff --git a/charts/visual-tom/values-client-template.yaml b/charts/visual-tom/values-client-template.yaml index 050b633..1a9ffdc 100644 --- a/charts/visual-tom/values-client-template.yaml +++ b/charts/visual-tom/values-client-template.yaml @@ -3,12 +3,7 @@ # # This file contains ONLY the values specific to your deployment. # It is layered on top of the chosen cloud profile (values-azure.yaml, etc.) -# -# Deployment: -# helm install vtom ./helm/vtom \ -# -f values-azure.yaml \ ← cloud profile (choose the right one) -# -f values-mycompany.yaml \ ← this file renamed -# --namespace vtom- --create-namespace +# See README.md / README-fr.md for full deployment instructions. # ============================================================================= # Target Kubernetes namespace — REQUIRED (must match the --namespace of helm install) @@ -32,11 +27,11 @@ vtom: repository: "visual-tom-core" tag: "" # TODO: VTOM version, e.g.: "7.3.2a" - # Internal VTOM server name — must match the VTOM registration - # and the license (the license is tied to this name). - # DO NOT change even if multiple instances coexist on the cluster: - # each instance is in a different namespace, so the K8s FQDN is unique - # (e.g.: vtom-server.vtom-client-a.svc.cluster.local). + # Name sent to agents so they can report job execution status back to the server. + # Must be resolvable by the agents — set this to serverService.hostname (or the + # LoadBalancer IP if no DNS hostname is assigned). The K8s service name (default + # "vtom-server") is only reachable inside the cluster and cannot be used by + # external agents. serverName: vtom-server # Domain name for the web interface (vtom-apiserver) @@ -52,7 +47,8 @@ vtom: database: name: vtom # TODO: PostgreSQL VTOM database name (e.g.: vtom, visual_tom) - # LoadBalancer Service for the VTOM Desktop Client (TCP ports 30xxx) + # LoadBalancer Service for external VTOM access (TCP ports 30xxx): + # VTOM Desktop Client (IHM Java), external agents returning job status, vtom CLI serverService: # Static IP — pre-reserve in your cloud provider to survive LB reprovisioning. # Leave empty to let the cloud assign a dynamic IP. @@ -80,12 +76,13 @@ vtom: # nodeSelector: # agentpool: vtom # affinity: {} - # Outbound traffic from vtom-apiserver to an external endpoint. - # TODO: change only if your external service uses a different TCP port. - apiserverExternalEgress: - port: "" # TODO: e.g.: 30034 (leave empty to disable this rule) - # TODO: restrict to the target CIDR whenever possible (avoid 0.0.0.0/0 in production). - cidr: "0.0.0.0/0" + # Outbound rules from vtom-apiserver to external endpoints (e.g. MFT on a remote cluster). + # Each entry creates one egress NetworkPolicy rule. Leave empty (default) to disable. + # TODO: restrict cidr to the target subnet whenever possible (avoid 0.0.0.0/0 in production). + apiserverExternalEgress: [] + # - port: 30034 # TODO: port of the target service + # protocol: TCP + # cidr: "10.0.0.0/8" # ----------------------------------------------------------------------------- # ITC (Visual TOM User Portal) diff --git a/charts/visual-tom/values.yaml b/charts/visual-tom/values.yaml index 08e801c..c4f51d1 100644 --- a/charts/visual-tom/values.yaml +++ b/charts/visual-tom/values.yaml @@ -155,13 +155,12 @@ vtom: tolerations: [] nodeSelector: {} affinity: {} - # Dedicated outbound rule for vtom-apiserver (external integration endpoint). - apiserverExternalEgress: - # Leave empty to disable this dedicated egress rule. - port: "" - # Destination CIDR allowed for the dedicated outbound rule above. - # Keep as narrow as possible in production. - cidr: "0.0.0.0/0" + # Outbound rules for vtom-apiserver to external endpoints (e.g. MFT on another cluster). + # Each entry creates one egress NetworkPolicy rule. Leave empty to disable. + apiserverExternalEgress: [] + # - port: 30034 + # protocol: TCP + # cidr: "10.0.0.0/8" # restrict to the target CIDR whenever possible # ----------------------------------------------------------------------------- # ITC (Visual TOM User Portal) From 146b57248562ea44f7d3df0b14f043871d169bdc Mon Sep 17 00:00:00 2001 From: Charles-Antoine Dolbeau Date: Fri, 29 May 2026 14:34:46 +0200 Subject: [PATCH 2/3] fix: remove README files incorrectly placed inside charts/visual-tom/ READMEs belong at the repo root (already there on main), not duplicated inside the chart directory. Co-Authored-By: Claude Sonnet 4.6 --- charts/visual-tom/README-fr.md | 517 --------------------------------- charts/visual-tom/README.md | 517 --------------------------------- 2 files changed, 1034 deletions(-) delete mode 100644 charts/visual-tom/README-fr.md delete mode 100644 charts/visual-tom/README.md diff --git a/charts/visual-tom/README-fr.md b/charts/visual-tom/README-fr.md deleted file mode 100644 index cfd5c2f..0000000 --- a/charts/visual-tom/README-fr.md +++ /dev/null @@ -1,517 +0,0 @@ -# Visual TOM — Chart Helm Kubernetes -[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)  -[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md) - -Ce dépôt fournit un chart Helm pour déployer **Visual TOM (Absyss)** et ses produits associés sur Kubernetes : - -- **VTOM** — Ordonnanceur (core) -- **ITC** — Visual TOM User Portal -- **ITM** — Visual IT Messenger -- **MFT** — Visual TOM Managed File Transfer - -Cibles validées : - -| Environnement | Statut | -|---|---| -| Azure AKS | ✅ Validé | -| GCP GKE (Autopilot) | ✅ Validé | -| AWS EKS | ⚠️ Implémenté, non testé en production | -| On-premise / Minikube | ✅ Testé localement | - -# Disclaimer - -Ce chart Helm est fourni par Absyss SAS comme un **déploiement de référence** de Visual TOM sur Kubernetes. Il est conçu comme un **point de départ** qui doit être adapté par chaque client à son infrastructure, à ses exigences de sécurité et à ses contraintes opérationnelles (topologie réseau, gestion des secrets, classes de stockage, contrôleur Ingress, politiques RBAC, etc.). - -Le chart est distribué **tel quel**, sans garantie d'aucune sorte. Absyss SAS ne peut être tenu responsable des dommages résultant de son utilisation ou des adaptations effectuées par le client. - -Les contrats de support Visual TOM standard ne couvrent pas le chart Helm lui-même ni les adaptations Kubernetes côté client. Des jours de consulting peuvent être demandés pour accompagner le déploiement, la personnalisation ou la résolution de problèmes. - -# Prérequis - -## Tous les environnements -- **Visual TOM** ≥ 7.3.2c (versions inférieures non testées avec ce chart) -- **Kubernetes** ≥ 1.28 -- **Helm** ≥ 3.8 (requis pour l'installation depuis le registry OCI) -- **PostgreSQL 17** accessible depuis le cluster (VNet, VPC ou réseau local) -- Un **contrôleur Ingress** installé — **Traefik** est utilisé par défaut, nginx est également supporté -- **cert-manager** installé avec un `ClusterIssuer` configuré si vous utilisez Let's Encrypt (option TLS par défaut). L'installation et la configuration de cert-manager sont à la charge du client — le chart se contente de créer les ressources `Certificate`. Si vous fournissez vos propres certificats TLS (`tls.provider: secret`), cert-manager n'est pas nécessaire -- **ExternalDNS** (optionnel) — pour la gestion automatique des enregistrements DNS du service LoadBalancer. Sans ExternalDNS, les enregistrements DNS doivent être créés manuellement. Voir `vtom.serverService.hostname` dans les values -- Une **licence VTOM** valide et un accès à un registry d'images - -> **Accès réseau privé / VPN :** les ressources type WireGuard, Private Endpoint, Cloud SQL Auth Proxy, etc. ne font **pas** partie de ce chart. Elles sont à provisionner en amont via votre IaC (Terraform, Bicep, etc.). - -## Prérequis cloud-spécifiques - -### Azure (AKS) -- ACR (Azure Container Registry) avec les images VTOM/ITC/ITM/MFT chargées -- Azure Key Vault avec les secrets créés (voir section Azure ci-dessous) -- User-Assigned Managed Identity avec accès Key Vault (`Key Vault Secrets User`) -- External Secrets Operator installé dans le cluster - -### AWS (EKS) -- ECR ou autre registry avec les images chargées -- AWS Secrets Manager avec les secrets créés -- IAM Role avec accès Secrets Manager, associé au ServiceAccount via IRSA -- External Secrets Operator installé dans le cluster - -### GCP (GKE) -- Artifact Registry ou GCR avec les images chargées -- GCP Secret Manager avec les secrets créés -- GCP Service Account avec accès Secret Manager, lié via Workload Identity -- External Secrets Operator installé dans le cluster -- Cloud SQL Auth Proxy activé dans les valeurs (préconfiguré dans `values-gcp.yaml`) - -### On-premise -- Registry Docker local ou images chargées manuellement (`docker load`) -- PostgreSQL accessible depuis les pods -- Secrets Kubernetes créés manuellement (voir section on-premise ci-dessous) -- Une **implémentation LoadBalancer** telle que [MetalLB](https://metallb.universe.tf/) — requise pour qu'une IP soit assignée aux Services `vtom-server` et `mft-sftp`. Sans cela, les Services `type: LoadBalancer` restent indéfiniment en état ``. Sur les clusters bare-metal ou locaux (RKE2, kubeadm, Minikube), ceci n'est pas fourni par défaut - -# Produits - -Le chart déploie 4 produits Visual TOM, chacun activable indépendamment via son toggle `.enabled`. Tous se partagent les paramètres globaux (registry, namespace, base de données, exposition réseau, NetworkPolicy). - -## VTOM — Ordonnanceur - -Le cœur de Visual TOM. Trois composants déployés en pods distincts, partageant la même image. - -| Composant | Rôle | Service | PVC | Mémoire (limite) | -|---|---|---|---|---| -| `vtom-server` | Moteur d'ordonnancement | LoadBalancer (5 ports natifs VTOM) | 5 Gi | 1 Gi | -| `vtom-apiserver` | API REST + interface web | ClusterIP + Ingress HTTPS | 2 Gi | 1.5 Gi | -| `vtom-agent` | Exécution des jobs Kubernetes | (aucun) | 10 Gi | 256 Mi | - -**Paramètres typiques :** -- `vtom.image.tag` — version VTOM (ex. `7.3.2c`) -- `vtom.ingress.host` — FQDN apiserver, ex. `vtom.mycompany.com` -- `vtom.serverService.hostname` — FQDN client VTOM Desktop (géré par ExternalDNS) -- `vtom.serverService.loadBalancerIP` — IP statique pour survivre aux reprovisions du LB -- `vtom.timezone` — fuseau horaire partagé (défaut `Europe/Paris`) -- `vtom.{server,apiserver,agent}Resources` — CPU/mémoire par composant -- `vtom.{server,apiserver,agent}Pvc.size` — tailles de stockage - -**Licence :** `vtom.license.secretName` (défaut `vtom-license-secret`) — partagée avec ITC et ITM par défaut. - -**Base :** DB nommée `vtom`, secret `vtom-db-secret` (clés `TOM_SGBD_USER` + `TOM_SGBD_PASSWORD` — mot de passe **chiffré format VTOM**, cf. [Format des secrets](#format-des-secrets)). - -**Désactiver :** `vtom.enabled: false` (utile si vous déployez uniquement ITC/ITM/MFT contre un serveur VTOM externe). - -## ITC — Visual TOM User Portal - -Portail utilisateur web pour piloter VTOM (visualisation, supervision, drag & drop). - -| Composant | Rôle | Service | PVC | Mémoire (limite) | -|---|---|---|---|---| -| `itc` | Portail web utilisateur | ClusterIP + Ingress HTTPS | 2 Gi | 1 Gi | - -**Paramètres typiques :** -- `itc.image.tag` — version ITC (**requise** si `itc.enabled=true`) -- `itc.ingress.host` — FQDN ITC, ex. `vitc.mycompany.com` -- `itc.resources`, `itc.pvc.size` - -**Licence :** par défaut réutilise la licence VTOM (`itc.license.secretName: vtom-license-secret`). - -**Base :** DB nommée `ITCockpits`, secret `itc-db-secret` (clés `ITDB_USER` + `ITDB_PASSWORD` — mot de passe **en clair**). - -**Désactiver :** `itc.enabled: false`. - -## ITM — Visual IT Messenger - -Service de messagerie / notification (envoi de courriels, alertes intégrées au workflow VTOM). - -| Composant | Rôle | Service | PVC | Mémoire (limite) | -|---|---|---|---|---| -| `itm` | Messenger | ClusterIP + Ingress HTTPS | 2 Gi | 1 Gi | - -**Paramètres typiques :** -- `itm.image.tag` — version ITM (**requise** si `itm.enabled=true`) -- `itm.ingress.host` — FQDN ITM, ex. `vitm.mycompany.com` -- `itm.resources`, `itm.pvc.size` - -**Licence :** par défaut réutilise la licence VTOM (`itm.license.secretName: vtom-license-secret`). - -**Base :** DB nommée `ITMessenger`, secret `itm-db-secret` (clés `ITDB_USER` + `ITDB_PASSWORD` — mot de passe **en clair**). - -**Désactiver :** `itm.enabled: false`. - -## MFT — Visual TOM Managed File Transfer - -Transferts de fichiers managés : serveur SFTP entrant + connecteurs sortants vers backends externes (NFS, S3, Azure Blob, FTP, SFTP). **Pas de base de données ni de licence séparée.** - -| Composant | Rôle | Services | PVC | Mémoire (limite) | -|---|---|---|---|---| -| `vtom-mft` | Portail HTTPS + serveur SFTP | `mft` (ClusterIP) + `mft-sftp` (LoadBalancer) + Ingress HTTPS | 1 Gi | 1 Gi | - -**Ports exposés :** -- `30034` — portail HTTPS (TLS auto-signé côté pod) -- `30022` — SFTP (accès clients externes via LoadBalancer) - -**Paramètres typiques :** -- `mft.image.tag` — version MFT (**requise** si `mft.enabled=true`) -- `mft.ingress.host` — FQDN portail web, ex. `mft.mycompany.com` -- `mft.sftpService.hostname` — FQDN SFTP (géré par ExternalDNS) -- `mft.sftpService.loadBalancerIP` — IP statique du LB SFTP -- `mft.sftpService.loadBalancerSourceRanges` — **toujours renseigner en production** pour restreindre l'accès SFTP par IP -- `mft.externalEgress` — règles NetworkPolicy de sortie vers les backends de stockage (NFS, S3, FTP, SFTP) -- `mft.pvcSeed.enabled` — init container qui prépare la structure du PVC au premier démarrage - -**Désactiver :** `mft.enabled: false`. - -# Installation - -## Depuis le registry public OCI (recommandé) - -Le chart est publié en tant qu'artefact OCI sur GitHub Container Registry. Aucune authentification requise. - -**Étape 1 — Récupérer le chart en local** : -```bash -helm pull oci://ghcr.io/absysslab/visual-tom --version 0.1.0 --untar -``` -Cette commande télécharge le chart et le dépaquette dans un dossier `visual-tom/` contenant `Chart.yaml`, `values.yaml`, tous les `values-.yaml`, le `values-client-template.yaml` et les `templates/`. - -**Étape 2 — Préparer votre fichier de valeurs client** : -```bash -cp visual-tom/values-client-template.yaml values-monentreprise.yaml -# Éditer values-monentreprise.yaml et remplir les lignes marquées « # TODO » -``` - -**Étape 3 — Installer** : -```bash -helm install visual-tom ./visual-tom \ - -f visual-tom/values-azure.yaml \ - -f values-monentreprise.yaml \ - --namespace vtom --create-namespace -``` - -Remplacer `values-azure.yaml` par `values-aws.yaml`, `values-gcp.yaml` ou `values-onpremise.yaml` selon votre cible. - -> **Mises à jour** : pour passer à une version ultérieure (ex. 0.1.1), relancer l'étape 1 avec `--version 0.1.1`, vérifier les changements éventuels dans les `values-.yaml`, puis `helm upgrade visual-tom ./visual-tom -f ... -f values-monentreprise.yaml --namespace vtom`. - -## Depuis les sources - -```bash -git clone https://github.com/AbsyssLab/vtom-helm.git -cd vtom-helm - -helm install visual-tom ./charts/visual-tom \ - -f ./charts/visual-tom/values-azure.yaml \ - -f values-monentreprise.yaml \ - --namespace vtom --create-namespace -``` - -# Configuration - -## Superposition des fichiers de valeurs - -Helm fusionne les fichiers de valeurs dans l'ordre indiqué sur la ligne de commande. Chaque fichier suivant écrase les valeurs du précédent : - -``` -values.yaml (defaults internes, chargé automatiquement) - + -values-.yaml (remplace les defaults par les valeurs cloud-spécifiques) - + -values-monentreprise.yaml (remplace par VOS valeurs spécifiques) - = -configuration finale déployée -``` - -## Étapes - -1. **Copier** `values-client-template.yaml` → `values-monentreprise.yaml` -2. **Remplir** toutes les lignes marquées `# TODO` -3. **Ne pas modifier** `values.yaml` ni les fichiers `values-.yaml` - -## Exposition réseau - -Par défaut, **tout est privé en production**. Le chart impose un Load Balancer interne pour `vtom.serverService` (VTOM Desktop) et `mft.sftpService` (SFTP) via des annotations spécifiques à chaque cloud, déjà configurées dans les fichiers `values-.yaml`. - -| Composant | Défaut | Override (public, tests) | Configuré dans | -|---|---|---|---| -| PostgreSQL | Endpoint privé (Private Endpoint, Private IP, VPC peering) | FQDN public | `database.host` — ce chart | -| vtom-server (VTOM Desktop) | LB interne — **imposé par le chart** | LB public | `vtom.serverService.annotations` — ce chart | -| MFT SFTP | LB interne — **imposé par le chart** | LB public | `mft.sftpService.annotations` — ce chart | -| Interfaces web (Ingress) | LB interne — **recommandé côté client** | LB public | Paramètres du contrôleur Ingress — **hors du chart** | - -**Annotations LB interne par cloud** (déjà configurées dans `values-.yaml`) : - -| Cloud | Annotations | -|---|---| -| Azure | `service.beta.kubernetes.io/azure-load-balancer-internal: "true"` | -| AWS | `aws-load-balancer-scheme: "internal"` (+ `aws-load-balancer-type: "external"`, `nlb-target-type: "ip"`) | -| GCP | `networking.gke.io/load-balancer-type: "Internal"` | -| On-premise | aucune — nécessite une implémentation LoadBalancer (ex. [MetalLB](https://metallb.universe.tf/)) | - -**Exposer publiquement (tests uniquement)** — surcharger les annotations dans `values-monentreprise.yaml` : -```yaml -vtom: - serverService: - annotations: {} # Désactive le LB interne - loadBalancerSourceRanges: - - "203.0.113.0/24" # Restreindre aux IPs autorisées -``` - -**Restreindre l'accès au LB interne par IP** (production) : -```yaml -vtom: - serverService: - loadBalancerSourceRanges: - - "10.0.0.0/8" # Réseau interne (VNet/VPC + VPN clients) -``` - -## Format des secrets - -Les conventions suivantes s'appliquent à **toutes les infrastructures** (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager, secrets Kubernetes natifs) : - -| Produit | Utilisateur DB | Mot de passe DB | -|---|---|---| -| **VTOM** | Texte brut | **Chiffré format VTOM** (bcrypt Absyss) — utiliser l'outil de chiffrement fourni par Absyss | -| **ITC** | Texte brut | **En clair** (ITC ne supporte pas le chiffrement VTOM) | -| **ITM** | Texte brut | **En clair** (ITM ne supporte pas le chiffrement VTOM) | - -> **Important :** ne **jamais** stocker le mot de passe VTOM en clair. Le format attendu est le hash bcrypt généré par l'outil Absyss. À l'inverse, les mots de passe ITC et ITM doivent rester en clair — toute tentative de chiffrement entraînera un échec de connexion. - -## Configuration par environnement - -### Azure (AKS) - -**Valeurs obligatoires :** - -| Paramètre | Description | Exemple | -|---|---|---| -| `global.imageRegistry` | Nom de l'ACR | `monacr.azurecr.io` | -| `vtom.image.tag` | Version VTOM | `7.3.2c` | -| `itc.image.tag` | Version ITC | `7.3.2c` | -| `itm.image.tag` | Version ITM | `7.3.2c` | -| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | -| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | -| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | -| `database.host` | FQDN PostgreSQL | `vtom-pg.postgres.database.azure.com` | -| `secrets.azure.keyVaultUrl` | URL du Key Vault | `https://mon-kv.vault.azure.net` | -| `secrets.azure.tenantId` | ID du tenant Azure AD | `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | -| `serviceAccount.azure.clientId` | Client ID de la Managed Identity | `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy` | - -**Secrets à créer dans Azure Key Vault :** - -| Nom du secret | Contenu | Format | -|---|---|---| -| `vtom-db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | -| `vtom-db-password` | Mot de passe VTOM pour PostgreSQL | **Chiffré format VTOM** (bcrypt Absyss) | -| `vtom-license-register` | Contenu du fichier `license.register` | Texte brut | -| `itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | -| `itc-db-password` | Mot de passe ITC pour PostgreSQL | **En clair** | -| `itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | -| `itm-db-password` | Mot de passe ITM pour PostgreSQL | **En clair** | - -> **PostgreSQL — privé vs public :** sur Azure, utilisez de préférence un **Private Endpoint** sur le serveur PostgreSQL flexible (FQDN `.private.postgres.database.azure.com`). Le FQDN public Azure (`.postgres.database.azure.com`) ne doit être utilisé qu'en test, avec firewall PostgreSQL restreint à votre VNet. - -### AWS (EKS) - -**Valeurs obligatoires :** - -| Paramètre | Description | Exemple | -|---|---|---| -| `global.imageRegistry` | Registry ECR | `123456789.dkr.ecr.eu-west-1.amazonaws.com` | -| `vtom.image.tag` | Version VTOM | `7.3.2c` | -| `itc.image.tag` | Version ITC | `7.3.2c` | -| `itm.image.tag` | Version ITM | `7.3.2c` | -| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | -| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | -| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | -| `database.host` | Endpoint RDS | `vtom.xxxx.eu-west-1.rds.amazonaws.com` | -| `secrets.aws.region` | Région AWS | `eu-west-1` | -| `serviceAccount.aws.roleArn` | ARN du rôle IAM | `arn:aws:iam::123456789012:role/vtom-role` | - -**Secrets à créer dans AWS Secrets Manager :** - -| Nom du secret | Contenu | Format | -|---|---|---| -| `vtom/db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | -| `vtom/db-password` | Mot de passe VTOM | **Chiffré format VTOM** | -| `vtom/license-register` | Fichier `license.register` | Texte brut | -| `vtom/itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | -| `vtom/itc-db-password` | Mot de passe ITC | **En clair** | -| `vtom/itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | -| `vtom/itm-db-password` | Mot de passe ITM | **En clair** | - -### GCP (GKE) - -**Valeurs obligatoires :** - -| Paramètre | Description | Exemple | -|---|---|---| -| `global.imageRegistry` | Artifact Registry | `europe-west1-docker.pkg.dev/mon-projet/vtom` | -| `vtom.image.tag` | Version VTOM | `7.3.2c` | -| `itc.image.tag` | Version ITC | `7.3.2c` | -| `itm.image.tag` | Version ITM | `7.3.2c` | -| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.com` | -| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.com` | -| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.com` | -| `dbProxy.cloudsqlProxy.instanceConnectionName` | Instance Cloud SQL | `mon-projet:europe-west1:vtom-postgres` | -| `secrets.gcp.projectId` | ID du projet GCP | `mon-projet-gcp` | -| `serviceAccount.gcp.serviceAccount` | GSA liée au KSA | `vtom@mon-projet.iam.gserviceaccount.com` | - -**Secrets à créer dans GCP Secret Manager :** - -| Nom du secret | Contenu | Format | -|---|---|---| -| `vtom-db-user` | Utilisateur PostgreSQL pour VTOM | Texte brut | -| `vtom-db-password` | Mot de passe VTOM | **Chiffré format VTOM** | -| `vtom-license-register` | Fichier `license.register` | Texte brut | -| `itc-db-user` | Utilisateur PostgreSQL pour ITC | Texte brut | -| `itc-db-password` | Mot de passe ITC | **En clair** | -| `itm-db-user` | Utilisateur PostgreSQL pour ITM | Texte brut | -| `itm-db-password` | Mot de passe ITM | **En clair** | - -### On-premise / RKE2 / Minikube - -**Valeurs obligatoires :** - -| Paramètre | Description | Exemple | -|---|---|---| -| `global.imageRegistry` | Registry local | `registry.monentreprise.com` | -| `vtom.image.tag` | Version VTOM | `7.3.2c` | -| `itc.image.tag` | Version ITC | `7.3.2c` | -| `itm.image.tag` | Version ITM | `7.3.2c` | -| `vtom.ingress.host` | Domaine VTOM | `vtom.monentreprise.local` | -| `itc.ingress.host` | Domaine ITC | `vitc.monentreprise.local` | -| `itm.ingress.host` | Domaine ITM | `vitm.monentreprise.local` | -| `database.host` | Hostname/IP PostgreSQL | `192.168.1.50` | - -**Secrets Kubernetes à créer manuellement avant le déploiement :** - -```bash -kubectl create namespace vtom - -# Utilisateur + mot de passe VTOM (mot de passe CHIFFRÉ au format VTOM — bcrypt Absyss) -kubectl create secret generic vtom-db-secret \ - --from-literal=TOM_SGBD_USER='' \ - --from-literal=TOM_SGBD_PASSWORD='' \ - -n vtom - -# Licence VTOM/ITC/ITM (fichier fourni par Absyss) -kubectl create secret generic vtom-license-secret \ - --from-file=license.register=/chemin/vers/license.register \ - -n vtom - -# Utilisateur + mot de passe ITC — EN CLAIR -kubectl create secret generic itc-db-secret \ - --from-literal=ITDB_USER='' \ - --from-literal=ITDB_PASSWORD='' \ - -n vtom - -# Utilisateur + mot de passe ITM — EN CLAIR -kubectl create secret generic itm-db-secret \ - --from-literal=ITDB_USER='' \ - --from-literal=ITDB_PASSWORD='' \ - -n vtom -``` - -## NetworkPolicy — Health checks Load Balancer - -Pour que les Load Balancers cloud puissent vérifier la santé des pods (probes), les CIDRs d'origine des probes doivent être explicitement autorisés dans la NetworkPolicy. Configurez `networkPolicy.lbHealthCheckCidrs` selon votre cloud : - -| Cloud | Valeur recommandée | -|---|---| -| Azure | `["168.63.129.16/32"]` | -| AWS | CIDR du VPC (ex. `["172.31.0.0/16"]`) — ne **pas** utiliser `["0.0.0.0/0"]` en production | -| GCP | `["130.211.0.0/22", "35.191.0.0/16"]` (Internal LB utilise les deux ranges) | -| On-premise | `[]` (pas de probe cloud) | - -Les fichiers `values-.yaml` fournissent déjà la bonne valeur par défaut. - -# Architecture - -![Architecture VTOM sur Kubernetes](architecture.png) - -# Mise à jour - -```bash -# Via OCI -helm upgrade visual-tom oci://ghcr.io/absysslab/visual-tom \ - --version 0.1.1 \ - -f values-azure.yaml \ - -f values-monentreprise.yaml \ - --namespace vtom - -# Depuis les sources -helm upgrade visual-tom ./charts/visual-tom \ - -f ./charts/visual-tom/values-azure.yaml \ - -f values-monentreprise.yaml \ - --namespace vtom -``` - -# Désinstallation - -```bash -helm uninstall visual-tom -n vtom -``` - -Par défaut, **les PersistentVolumeClaims (PVC) et les PersistentVolumes (PV) sous-jacents sont conservés** (`reclaimPolicy: Retain`). Cela protège vos données (clés de chiffrement, logs, journaux, configuration) contre une suppression accidentelle. - -> ⚠️ **AVERTISSEMENT — Perte de données irréversible** -> -> Les commandes ci-dessous suppriment définitivement **toutes les données VTOM, ITC, ITM et MFT**. Sur Azure / AWS / GCP, le disque cloud sous-jacent est également supprimé. **Aucune restauration n'est possible sans sauvegarde préalable**. -> -> N'exécuter qu'après avoir : -> - Effectué un dump complet de PostgreSQL -> - Sauvegardé les fichiers de configuration et journaux des PVC -> - Confirmé que ces données ne sont plus nécessaires - -```bash -# 1. Supprimer les PVC (libère les PV qui passent en état "Released") -kubectl delete pvc --all -n vtom - -# 2. Supprimer les PV libérés (perte définitive des disques sous-jacents) -kubectl get pv | grep "vtom/" | awk '{print $1}' | xargs -r kubectl delete pv - -# 3. (Optionnel) Supprimer le namespace -kubectl delete namespace vtom -``` - -# Vérification du déploiement - -```bash -kubectl get pods -n vtom -kubectl get ingress -n vtom -kubectl get svc -n vtom -helm status visual-tom -n vtom -``` - -# Résolution de problèmes - -**Les pods restent en `Pending` :** -```bash -kubectl describe pod -n vtom -# Vérifier les events — souvent un problème de PVC ou de ressources insuffisantes -``` - -**Les pods restent en `Init:0/1` ou `Init:Error` :** -```bash -kubectl logs -n vtom -c wait-for-db -# Le proxy DB ne démarre pas ou la DB est inaccessible -``` - -**Les secrets ESO ne se synchronisent pas :** -```bash -kubectl get externalsecret -n vtom -kubectl describe externalsecret vtom-db-secret -n vtom -# Vérifier les permissions de la Managed Identity / IAM Role / GSA sur le coffre de secrets -``` - -**Le certificat TLS n'est pas émis :** -```bash -kubectl get certificate -n vtom -kubectl describe certificate vtom-tls-cert -n vtom -# Vérifier que le ClusterIssuer est prêt et que le domaine est accessible depuis internet -``` - -**Le Load Balancer reste `` ou les probes échouent :** -```bash -kubectl describe svc vtom-server -n vtom -# Côté NetworkPolicy : vérifier networkPolicy.lbHealthCheckCidrs (cf. section dédiée) -# Côté cloud : vérifier annotations et quotas LB -``` - -# Licence - -Ce projet est sous licence Apache 2.0. Voir le fichier [LICENSE](LICENSE) pour plus de détails. diff --git a/charts/visual-tom/README.md b/charts/visual-tom/README.md deleted file mode 100644 index 1947a66..0000000 --- a/charts/visual-tom/README.md +++ /dev/null @@ -1,517 +0,0 @@ -# Visual TOM — Kubernetes Helm Chart -[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)  -[![fr](https://img.shields.io/badge/lang-fr-yellow.svg)](README-fr.md) - -This repository provides a Helm chart to deploy **Visual TOM (Absyss)** and its related products on Kubernetes: - -- **VTOM** — Scheduler (core) -- **ITC** — Visual TOM User Portal -- **ITM** — Visual IT Messenger -- **MFT** — Visual TOM Managed File Transfer - -Validated targets: - -| Environment | Status | -|---|---| -| Azure AKS | ✅ Validated | -| GCP GKE (Autopilot) | ✅ Validated | -| AWS EKS | ⚠️ Implemented, not tested in production | -| On-premise / Minikube | ✅ Tested locally | - -# Disclaimer - -This Helm chart is provided by Absyss SAS as a **reference deployment** of Visual TOM on Kubernetes. It is designed as a **starting point** that must be adapted by each client to match their specific infrastructure, security requirements and operational constraints (network topology, secrets management, storage classes, ingress controller, RBAC policies, etc.). - -The chart is distributed **as-is**, without warranty of any kind. Absyss SAS is not liable for damages resulting from its use or from client-side adaptations. - -Standard Visual TOM support contracts do not cover the Helm chart itself or client-side Kubernetes adaptations. Consulting days can be requested to assist with deployment, customization or troubleshooting. - -# Prerequisites - -## All environments -- **Visual TOM** ≥ 7.3.2c (earlier versions are not tested with this chart) -- **Kubernetes** ≥ 1.28 -- **Helm** ≥ 3.8 (required to install from the OCI registry) -- **PostgreSQL 17** reachable from the cluster (VNet, VPC or local network) -- An **Ingress controller** installed — **Traefik** is used by default, nginx is also supported -- **cert-manager** installed with a `ClusterIssuer` configured if you use Let's Encrypt (default TLS option). Installing and configuring cert-manager is the client's responsibility — the chart only creates the `Certificate` resources. If you provide your own TLS certificates (`tls.provider: secret`), cert-manager is not required -- **ExternalDNS** (optional) — for automatic DNS record management of the LoadBalancer service. Without ExternalDNS, DNS records must be created manually. See `vtom.serverService.hostname` in the values -- A valid **VTOM license** and access to an image registry - -> **Private network access / VPN:** resources such as WireGuard, Private Endpoints, Cloud SQL Auth Proxy, etc. are **not** part of this chart. They must be provisioned upstream via your IaC (Terraform, Bicep, etc.). - -## Cloud-specific prerequisites - -### Azure (AKS) -- ACR (Azure Container Registry) with the VTOM/ITC/ITM/MFT images loaded -- Azure Key Vault with the secrets created (see Azure section below) -- User-Assigned Managed Identity with Key Vault access (`Key Vault Secrets User`) -- External Secrets Operator installed in the cluster - -### AWS (EKS) -- ECR or another registry with the images loaded -- AWS Secrets Manager with the secrets created -- IAM Role with Secrets Manager access, associated with the ServiceAccount via IRSA -- External Secrets Operator installed in the cluster - -### GCP (GKE) -- Artifact Registry or GCR with the images loaded -- GCP Secret Manager with the secrets created -- GCP Service Account with Secret Manager access, linked via Workload Identity -- External Secrets Operator installed in the cluster -- Cloud SQL Auth Proxy enabled in the values (preconfigured in `values-gcp.yaml`) - -### On-premise -- Local Docker registry or images loaded manually (`docker load`) -- PostgreSQL reachable from the pods -- Kubernetes secrets created manually (see on-premise section below) -- A **LoadBalancer implementation** such as [MetalLB](https://metallb.universe.tf/) — required to assign an IP to `vtom-server` and `mft-sftp` Services. Without it, `type: LoadBalancer` Services remain in `` state indefinitely. On bare-metal or local clusters (RKE2, kubeadm, Minikube), this is not provided by default - -# Products - -The chart deploys 4 Visual TOM products, each independently toggleable via its `.enabled` flag. They all share global settings (registry, namespace, database, network exposure, NetworkPolicy). - -## VTOM — Scheduler - -The core of Visual TOM. Three components deployed as separate pods, sharing the same image. - -| Component | Role | Service | PVC | Memory (limit) | -|---|---|---|---|---| -| `vtom-server` | Scheduling engine | LoadBalancer (5 native VTOM ports) | 5 Gi | 1 Gi | -| `vtom-apiserver` | REST API + web interface | ClusterIP + HTTPS Ingress | 2 Gi | 1.5 Gi | -| `vtom-agent` | Kubernetes job executor | (none) | 10 Gi | 256 Mi | - -**Typical parameters:** -- `vtom.image.tag` — VTOM version (e.g. `7.3.2c`) -- `vtom.ingress.host` — apiserver FQDN, e.g. `vtom.mycompany.com` -- `vtom.serverService.hostname` — VTOM Desktop client FQDN (managed by ExternalDNS) -- `vtom.serverService.loadBalancerIP` — static IP to survive LB reprovisioning -- `vtom.timezone` — shared timezone (default `Europe/Paris`) -- `vtom.{server,apiserver,agent}Resources` — CPU/memory per component -- `vtom.{server,apiserver,agent}Pvc.size` — storage sizes - -**License:** `vtom.license.secretName` (default `vtom-license-secret`) — shared with ITC and ITM by default. - -**Database:** DB named `vtom`, secret `vtom-db-secret` (keys `TOM_SGBD_USER` + `TOM_SGBD_PASSWORD` — password **VTOM-encrypted**, see [Secret formats](#secret-formats)). - -**Disable:** `vtom.enabled: false` (useful if you only deploy ITC/ITM/MFT against an external VTOM server). - -## ITC — Visual TOM User Portal - -Web user portal to operate VTOM (visualization, monitoring, drag & drop). - -| Component | Role | Service | PVC | Memory (limit) | -|---|---|---|---|---| -| `itc` | Web user portal | ClusterIP + HTTPS Ingress | 2 Gi | 1 Gi | - -**Typical parameters:** -- `itc.image.tag` — ITC version (**required** if `itc.enabled=true`) -- `itc.ingress.host` — ITC FQDN, e.g. `vitc.mycompany.com` -- `itc.resources`, `itc.pvc.size` - -**License:** by default reuses the VTOM license (`itc.license.secretName: vtom-license-secret`). - -**Database:** DB named `ITCockpits`, secret `itc-db-secret` (keys `ITDB_USER` + `ITDB_PASSWORD` — password **plain text**). - -**Disable:** `itc.enabled: false`. - -## ITM — Visual IT Messenger - -Messaging / notification service (email sending, alerts integrated into the VTOM workflow). - -| Component | Role | Service | PVC | Memory (limit) | -|---|---|---|---|---| -| `itm` | Messenger | ClusterIP + HTTPS Ingress | 2 Gi | 1 Gi | - -**Typical parameters:** -- `itm.image.tag` — ITM version (**required** if `itm.enabled=true`) -- `itm.ingress.host` — ITM FQDN, e.g. `vitm.mycompany.com` -- `itm.resources`, `itm.pvc.size` - -**License:** by default reuses the VTOM license (`itm.license.secretName: vtom-license-secret`). - -**Database:** DB named `ITMessenger`, secret `itm-db-secret` (keys `ITDB_USER` + `ITDB_PASSWORD` — password **plain text**). - -**Disable:** `itm.enabled: false`. - -## MFT — Visual TOM Managed File Transfer - -Managed file transfers: inbound SFTP server + outbound connectors to external backends (NFS, S3, Azure Blob, FTP, SFTP). **No database, no separate license.** - -| Component | Role | Services | PVC | Memory (limit) | -|---|---|---|---|---| -| `vtom-mft` | HTTPS portal + SFTP server | `mft` (ClusterIP) + `mft-sftp` (LoadBalancer) + HTTPS Ingress | 1 Gi | 1 Gi | - -**Exposed ports:** -- `30034` — HTTPS portal (self-signed TLS served by the pod) -- `30022` — SFTP (external client access via LoadBalancer) - -**Typical parameters:** -- `mft.image.tag` — MFT version (**required** if `mft.enabled=true`) -- `mft.ingress.host` — web portal FQDN, e.g. `mft.mycompany.com` -- `mft.sftpService.hostname` — SFTP FQDN (managed by ExternalDNS) -- `mft.sftpService.loadBalancerIP` — static IP of the SFTP LB -- `mft.sftpService.loadBalancerSourceRanges` — **always set in production** to restrict SFTP access by IP -- `mft.externalEgress` — egress NetworkPolicy rules to storage backends (NFS, S3, FTP, SFTP) -- `mft.pvcSeed.enabled` — init container that prepares the PVC structure on first startup - -**Disable:** `mft.enabled: false`. - -# Installation - -## From the public OCI registry (recommended) - -The chart is published as an OCI artifact on GitHub Container Registry. No authentication required. - -**Step 1 — Pull the chart locally**: -```bash -helm pull oci://ghcr.io/absysslab/visual-tom --version 0.1.0 --untar -``` -This downloads the chart and extracts it into a `visual-tom/` directory containing `Chart.yaml`, `values.yaml`, all `values-.yaml`, the `values-client-template.yaml` and the `templates/`. - -**Step 2 — Prepare your client values file**: -```bash -cp visual-tom/values-client-template.yaml values-mycompany.yaml -# Edit values-mycompany.yaml and fill in the lines marked "# TODO" -``` - -**Step 3 — Install**: -```bash -helm install visual-tom ./visual-tom \ - -f visual-tom/values-azure.yaml \ - -f values-mycompany.yaml \ - --namespace vtom --create-namespace -``` - -Replace `values-azure.yaml` with `values-aws.yaml`, `values-gcp.yaml` or `values-onpremise.yaml` according to your target. - -> **Upgrades**: to move to a later version (e.g. 0.1.1), re-run step 1 with `--version 0.1.1`, review any changes in the `values-.yaml`, then `helm upgrade visual-tom ./visual-tom -f ... -f values-mycompany.yaml --namespace vtom`. - -## From sources - -```bash -git clone https://github.com/AbsyssLab/vtom-helm.git -cd vtom-helm - -helm install visual-tom ./charts/visual-tom \ - -f ./charts/visual-tom/values-azure.yaml \ - -f values-mycompany.yaml \ - --namespace vtom --create-namespace -``` - -# Configuration - -## Values files layering - -Helm merges values files in the order they appear on the command line. Each subsequent file overrides the previous one: - -``` -values.yaml (internal defaults, loaded automatically) - + -values-.yaml (overrides defaults with cloud-specific values) - + -values-mycompany.yaml (overrides with YOUR specific values) - = -final deployed configuration -``` - -## Steps - -1. **Copy** `values-client-template.yaml` → `values-mycompany.yaml` -2. **Fill in** all lines marked `# TODO` -3. **Do not modify** `values.yaml` or any `values-.yaml` file - -## Network exposure - -By default, **everything is private in production**. The chart enforces an internal Load Balancer for `vtom.serverService` (VTOM Desktop) and `mft.sftpService` (SFTP) via cloud-specific annotations, already configured in the `values-.yaml` files. - -| Component | Default | Override (public, tests) | Configured in | -|---|---|---|---| -| PostgreSQL | Private endpoint (Private Endpoint, Private IP, VPC peering) | Public FQDN | `database.host` — this chart | -| vtom-server (VTOM Desktop) | Internal LB — **enforced by the chart** | Public LB | `vtom.serverService.annotations` — this chart | -| MFT SFTP | Internal LB — **enforced by the chart** | Public LB | `mft.sftpService.annotations` — this chart | -| Web interfaces (Ingress) | Internal LB — **recommended on the client side** | Public LB | Ingress controller settings — **out of scope of the chart** | - -**Internal LB annotations per cloud** (already configured in `values-.yaml`): - -| Cloud | Annotations | -|---|---| -| Azure | `service.beta.kubernetes.io/azure-load-balancer-internal: "true"` | -| AWS | `aws-load-balancer-scheme: "internal"` (+ `aws-load-balancer-type: "external"`, `nlb-target-type: "ip"`) | -| GCP | `networking.gke.io/load-balancer-type: "Internal"` | -| On-premise | none — requires a LoadBalancer implementation (e.g. [MetalLB](https://metallb.universe.tf/)) | - -**Expose publicly (tests only)** — override the annotations in `values-mycompany.yaml`: -```yaml -vtom: - serverService: - annotations: {} # Disables the internal LB - loadBalancerSourceRanges: - - "203.0.113.0/24" # Restrict to authorized IPs -``` - -**Restrict access to the internal LB by IP** (production): -```yaml -vtom: - serverService: - loadBalancerSourceRanges: - - "10.0.0.0/8" # Internal network (VNet/VPC + client VPN) -``` - -## Secret formats - -The following conventions apply to **all infrastructures** (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager, native Kubernetes secrets): - -| Product | DB user | DB password | -|---|---|---| -| **VTOM** | Plain text | **VTOM-encrypted** (Absyss bcrypt) — use the encryption tool provided by Absyss | -| **ITC** | Plain text | **Plain text** (ITC does not support VTOM encryption) | -| **ITM** | Plain text | **Plain text** (ITM does not support VTOM encryption) | - -> **Important:** never store the VTOM password in plain text. The expected format is the bcrypt hash generated by the Absyss tool. Conversely, ITC and ITM passwords must remain plain text — any encryption attempt will cause connection failures. - -## Configuration per environment - -### Azure (AKS) - -**Required values:** - -| Parameter | Description | Example | -|---|---|---| -| `global.imageRegistry` | ACR name | `myacr.azurecr.io` | -| `vtom.image.tag` | VTOM version | `7.3.2c` | -| `itc.image.tag` | ITC version | `7.3.2c` | -| `itm.image.tag` | ITM version | `7.3.2c` | -| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | -| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | -| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | -| `database.host` | PostgreSQL FQDN | `vtom-pg.postgres.database.azure.com` | -| `secrets.azure.keyVaultUrl` | Key Vault URL | `https://my-kv.vault.azure.net` | -| `secrets.azure.tenantId` | Azure AD tenant ID | `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | -| `serviceAccount.azure.clientId` | Managed Identity client ID | `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy` | - -**Secrets to create in Azure Key Vault:** - -| Secret name | Content | Format | -|---|---|---| -| `vtom-db-user` | PostgreSQL user for VTOM | Plain text | -| `vtom-db-password` | VTOM password for PostgreSQL | **VTOM-encrypted** (Absyss bcrypt) | -| `vtom-license-register` | Content of the `license.register` file | Plain text | -| `itc-db-user` | PostgreSQL user for ITC | Plain text | -| `itc-db-password` | ITC password for PostgreSQL | **Plain text** | -| `itm-db-user` | PostgreSQL user for ITM | Plain text | -| `itm-db-password` | ITM password for PostgreSQL | **Plain text** | - -> **PostgreSQL — private vs public:** on Azure, prefer a **Private Endpoint** on the PostgreSQL Flexible Server (FQDN `.private.postgres.database.azure.com`). The Azure public FQDN (`.postgres.database.azure.com`) should only be used in test, with the PostgreSQL firewall restricted to your VNet. - -### AWS (EKS) - -**Required values:** - -| Parameter | Description | Example | -|---|---|---| -| `global.imageRegistry` | ECR registry | `123456789.dkr.ecr.eu-west-1.amazonaws.com` | -| `vtom.image.tag` | VTOM version | `7.3.2c` | -| `itc.image.tag` | ITC version | `7.3.2c` | -| `itm.image.tag` | ITM version | `7.3.2c` | -| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | -| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | -| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | -| `database.host` | RDS endpoint | `vtom.xxxx.eu-west-1.rds.amazonaws.com` | -| `secrets.aws.region` | AWS region | `eu-west-1` | -| `serviceAccount.aws.roleArn` | IAM Role ARN | `arn:aws:iam::123456789012:role/vtom-role` | - -**Secrets to create in AWS Secrets Manager:** - -| Secret name | Content | Format | -|---|---|---| -| `vtom/db-user` | PostgreSQL user for VTOM | Plain text | -| `vtom/db-password` | VTOM password | **VTOM-encrypted** | -| `vtom/license-register` | `license.register` file | Plain text | -| `vtom/itc-db-user` | PostgreSQL user for ITC | Plain text | -| `vtom/itc-db-password` | ITC password | **Plain text** | -| `vtom/itm-db-user` | PostgreSQL user for ITM | Plain text | -| `vtom/itm-db-password` | ITM password | **Plain text** | - -### GCP (GKE) - -**Required values:** - -| Parameter | Description | Example | -|---|---|---| -| `global.imageRegistry` | Artifact Registry | `europe-west1-docker.pkg.dev/my-project/vtom` | -| `vtom.image.tag` | VTOM version | `7.3.2c` | -| `itc.image.tag` | ITC version | `7.3.2c` | -| `itm.image.tag` | ITM version | `7.3.2c` | -| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.com` | -| `itc.ingress.host` | ITC domain | `vitc.mycompany.com` | -| `itm.ingress.host` | ITM domain | `vitm.mycompany.com` | -| `dbProxy.cloudsqlProxy.instanceConnectionName` | Cloud SQL instance | `my-project:europe-west1:vtom-postgres` | -| `secrets.gcp.projectId` | GCP project ID | `my-gcp-project` | -| `serviceAccount.gcp.serviceAccount` | GSA linked to the KSA | `vtom@my-project.iam.gserviceaccount.com` | - -**Secrets to create in GCP Secret Manager:** - -| Secret name | Content | Format | -|---|---|---| -| `vtom-db-user` | PostgreSQL user for VTOM | Plain text | -| `vtom-db-password` | VTOM password | **VTOM-encrypted** | -| `vtom-license-register` | `license.register` file | Plain text | -| `itc-db-user` | PostgreSQL user for ITC | Plain text | -| `itc-db-password` | ITC password | **Plain text** | -| `itm-db-user` | PostgreSQL user for ITM | Plain text | -| `itm-db-password` | ITM password | **Plain text** | - -### On-premise / RKE2 / Minikube - -**Required values:** - -| Parameter | Description | Example | -|---|---|---| -| `global.imageRegistry` | Local registry | `registry.mycompany.com` | -| `vtom.image.tag` | VTOM version | `7.3.2c` | -| `itc.image.tag` | ITC version | `7.3.2c` | -| `itm.image.tag` | ITM version | `7.3.2c` | -| `vtom.ingress.host` | VTOM domain | `vtom.mycompany.local` | -| `itc.ingress.host` | ITC domain | `vitc.mycompany.local` | -| `itm.ingress.host` | ITM domain | `vitm.mycompany.local` | -| `database.host` | PostgreSQL hostname/IP | `192.168.1.50` | - -**Kubernetes secrets to create manually before deployment:** - -```bash -kubectl create namespace vtom - -# VTOM user + password (password VTOM-ENCRYPTED — Absyss bcrypt) -kubectl create secret generic vtom-db-secret \ - --from-literal=TOM_SGBD_USER='' \ - --from-literal=TOM_SGBD_PASSWORD='' \ - -n vtom - -# VTOM/ITC/ITM license (file provided by Absyss) -kubectl create secret generic vtom-license-secret \ - --from-file=license.register=/path/to/license.register \ - -n vtom - -# ITC user + password — PLAIN TEXT -kubectl create secret generic itc-db-secret \ - --from-literal=ITDB_USER='' \ - --from-literal=ITDB_PASSWORD='' \ - -n vtom - -# ITM user + password — PLAIN TEXT -kubectl create secret generic itm-db-secret \ - --from-literal=ITDB_USER='' \ - --from-literal=ITDB_PASSWORD='' \ - -n vtom -``` - -## NetworkPolicy — Load Balancer health checks - -For cloud Load Balancers to be able to probe pod health, the source CIDRs of the probes must be explicitly allowed in the NetworkPolicy. Configure `networkPolicy.lbHealthCheckCidrs` according to your cloud: - -| Cloud | Recommended value | -|---|---| -| Azure | `["168.63.129.16/32"]` | -| AWS | VPC CIDR (e.g. `["172.31.0.0/16"]`) — do **not** use `["0.0.0.0/0"]` in production | -| GCP | `["130.211.0.0/22", "35.191.0.0/16"]` (Internal LB uses both ranges) | -| On-premise | `[]` (no cloud probe) | - -The `values-.yaml` files already provide the correct default value. - -# Architecture - -![VTOM on Kubernetes architecture](architecture.png) - -# Upgrade - -```bash -# Via OCI -helm upgrade visual-tom oci://ghcr.io/absysslab/visual-tom \ - --version 0.1.1 \ - -f values-azure.yaml \ - -f values-mycompany.yaml \ - --namespace vtom - -# From sources -helm upgrade visual-tom ./charts/visual-tom \ - -f ./charts/visual-tom/values-azure.yaml \ - -f values-mycompany.yaml \ - --namespace vtom -``` - -# Uninstallation - -```bash -helm uninstall visual-tom -n vtom -``` - -By default, **PersistentVolumeClaims (PVCs) and the underlying PersistentVolumes (PVs) are retained** (`reclaimPolicy: Retain`). This protects your data (encryption keys, application logs, audit logs, configuration) against accidental deletion. - -> ⚠️ **WARNING — Irreversible data loss** -> -> The commands below permanently delete **all VTOM, ITC, ITM and MFT data**. On Azure / AWS / GCP, the underlying cloud disk is also deleted. **No restoration is possible without a prior backup**. -> -> Only run after you have: -> - Taken a complete PostgreSQL dump -> - Backed up the configuration files and logs from the PVCs -> - Confirmed that this data is no longer needed - -```bash -# 1. Delete the PVCs (releases the PVs, which transition to "Released" state) -kubectl delete pvc --all -n vtom - -# 2. Delete the released PVs (permanent loss of the underlying disks) -kubectl get pv | grep "vtom/" | awk '{print $1}' | xargs -r kubectl delete pv - -# 3. (Optional) Delete the namespace -kubectl delete namespace vtom -``` - -# Verifying the deployment - -```bash -kubectl get pods -n vtom -kubectl get ingress -n vtom -kubectl get svc -n vtom -helm status visual-tom -n vtom -``` - -# Troubleshooting - -**Pods stay in `Pending`:** -```bash -kubectl describe pod -n vtom -# Check the events — typically a PVC issue or insufficient resources -``` - -**Pods stay in `Init:0/1` or `Init:Error`:** -```bash -kubectl logs -n vtom -c wait-for-db -# The DB proxy is not starting or the DB is unreachable -``` - -**ESO secrets are not syncing:** -```bash -kubectl get externalsecret -n vtom -kubectl describe externalsecret vtom-db-secret -n vtom -# Check the permissions of the Managed Identity / IAM Role / GSA on the secret store -``` - -**The TLS certificate is not being issued:** -```bash -kubectl get certificate -n vtom -kubectl describe certificate vtom-tls-cert -n vtom -# Check that the ClusterIssuer is ready and the domain is reachable from the internet -``` - -**The Load Balancer stays `` or probes are failing:** -```bash -kubectl describe svc vtom-server -n vtom -# NetworkPolicy side: check networkPolicy.lbHealthCheckCidrs (see dedicated section) -# Cloud side: check annotations and LB quotas -``` - -# License - -This project is licensed under the Apache 2.0 License — see the [LICENSE](LICENSE) file for details. From 6a5a14dd2d92c355e7925eec0c8142149bc5604e Mon Sep 17 00:00:00 2001 From: Charles-Antoine Dolbeau Date: Fri, 29 May 2026 14:53:35 +0200 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20clarify=20serverName=20=E2=80=94=20?= =?UTF-8?q?DNS=20label=20only,=20tip=20for=20vtom.ini=20DomainName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serverName must be a simple hostname (no dots). Adding DomainName in vtom.ini makes VTOM send "." to agents. Co-Authored-By: Claude Sonnet 4.6 --- charts/visual-tom/values-client-template.yaml | 12 +++++++----- charts/visual-tom/values.yaml | 5 +++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/charts/visual-tom/values-client-template.yaml b/charts/visual-tom/values-client-template.yaml index 1a9ffdc..5655655 100644 --- a/charts/visual-tom/values-client-template.yaml +++ b/charts/visual-tom/values-client-template.yaml @@ -27,11 +27,13 @@ vtom: repository: "visual-tom-core" tag: "" # TODO: VTOM version, e.g.: "7.3.2a" - # Name sent to agents so they can report job execution status back to the server. - # Must be resolvable by the agents — set this to serverService.hostname (or the - # LoadBalancer IP if no DNS hostname is assigned). The K8s service name (default - # "vtom-server") is only reachable inside the cluster and cannot be used by - # external agents. + # Short hostname of the VTOM server — used as the K8s Service name and pod hostname. + # Must be a simple DNS label (lowercase, hyphens only — no dots, no FQDN). + # External agents must be able to resolve this name (set it to serverService.hostname + # or the LoadBalancer IP if no DNS hostname is assigned). The default K8s service name + # "vtom-server" is only reachable inside the cluster. + # Tip: add a "DomainName = mycompany.com" entry in the server's vtom.ini to have VTOM + # automatically send "." to agents instead of just serverName. serverName: vtom-server # Domain name for the web interface (vtom-apiserver) diff --git a/charts/visual-tom/values.yaml b/charts/visual-tom/values.yaml index c4f51d1..49e2220 100644 --- a/charts/visual-tom/values.yaml +++ b/charts/visual-tom/values.yaml @@ -43,8 +43,9 @@ vtom: pullPolicy: IfNotPresent # Internal VTOM name: hostname of the server pod and name of the K8s server Service. - # VTOM registers with this name; the agent calls back the server via this hostname. - # ITC connects to vtom-apiserver via this name (+ port 30002). + # Must be a valid DNS label (lowercase, hyphens only — no dots, no FQDN). + # Tip: add a "DomainName = mycompany.com" entry in the server's vtom.ini to have VTOM + # automatically send "." to agents instead of just serverName. serverName: vtom-server # Timezone shared by all VTOM components