From 31fd4e0b61061d9f2494040d1879f1f93eb15ac9 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Mon, 17 Aug 2026 08:54:53 +0200 Subject: [PATCH 1/3] Add production LocalEGA installation guide --- LEAME.md | 1135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1135 insertions(+) create mode 100644 LEAME.md diff --git a/LEAME.md b/LEAME.md new file mode 100644 index 00000000..8644b0d5 --- /dev/null +++ b/LEAME.md @@ -0,0 +1,1135 @@ +# Instalación limpia de LocalEGA con Podman rootless + +Esta guía describe una instalación limpia de LocalEGA en una VM Linux mediante Podman rootless. Incluye la preparación del host, el despliegue y la comprobación del flujo básico de subida, ingesta, autorización y descarga. + +La guía separa expresamente: + +- los datos de gran tamaño alojados en NFS; +- la configuración y el runtime alojados en disco local; +- los identificadores internos de los contenedores; +- los UID/GID subordinados que Podman representa en el host. + +No asume una instalación previa ni datos existentes. Las operaciones de actualización, migración y recuperación deben documentarse y ejecutarse por separado. + +## Índice + +- [Alcance](#alcance) +- [Arquitectura](#arquitectura) +- [Decisiones previas de infraestructura](#decisiones-previas-de-infraestructura) +- [Requisitos](#requisitos) +- [Usuario rootless y mapeo de IDs](#usuario-rootless-y-mapeo-de-ids) +- [Rutas persistentes](#rutas-persistentes) +- [Preparar las rutas y SELinux](#preparar-las-rutas-y-selinux) +- [Obtener el código](#obtener-el-código) +- [Generar las claves](#generar-las-claves) +- [Configurar el despliegue](#configurar-el-despliegue) +- [Preparar permisos](#preparar-permisos) +- [Construir las imágenes](#construir-las-imágenes) +- [Inicializar Vault DB](#inicializar-vault-db) +- [Arrancar LocalEGA](#arrancar-localega) +- [Configurar la limpieza del Inbox](#configurar-la-limpieza-del-inbox) +- [Arranque automático](#arranque-automático) +- [Validaciones](#validaciones) +- [Operación diaria](#operación-diaria) +- [Backups](#backups) +- [Actualización y rollback](#actualización-y-rollback) +- [Troubleshooting](#troubleshooting) +- [Checklist de producción](#checklist-de-producción) + +## Alcance + +Este documento cubre: + +- despliegue con Podman rootless; +- servicios `inbox`, `mq`, `handler`, `vault-db`, `distribution`, `nss-sync` e `inbox-cleaner`; +- persistencia en NFS y disco local; +- configuración centralizada en `deploy/docker/.env` siempre que el Compose lo permita; +- integración con CEGA TEST o CEGA de producción; +- validaciones de servicios, DNS, RabbitMQ, PostgreSQL, permisos y flujo funcional. + +No cubre: + +- alta administrativa del afiliado en CEGA; +- gestión funcional de submissions, datasets o DAC en portales externos; +- diseño de firewall, monitorización, backup o recuperación ante desastres; +- migración de una instalación existente. + +## Arquitectura + +| Componente | Función | +|---|---| +| `inbox` | Servicio SFTP de entrada para ficheros cifrados `.c4gh`. | +| `mq` | RabbitMQ local, conectado con CEGA mediante shovel/federation. | +| `handler` | Procesa eventos de ingesta, accession, mapping, release, permisos y claves. | +| `vault-db` | PostgreSQL con el estado y las funciones SQL de LocalEGA. | +| `distribution` | Servicio SFTP para descarga autorizada. | +| `nss-sync` | Sincroniza usuarios, grupos, claves y homes para `distribution`. | +| `inbox-cleaner` | Elimina de forma auditable ficheros del Inbox cuya ingesta finalizó y superó la retención configurada. | + +Puertos configurados en esta guía: + +| Variable | Puerto | Servicio | +|---|---:|---| +| `INBOX_PORT` | `8086` | SFTP Inbox | +| `MQ_MANAGEMENT_PORT` | `15672` | RabbitMQ Management | +| `VAULT_DB_PORT` | `5432` | PostgreSQL | +| `DISTRIBUTION_PORT` | `2224` | SFTP Distribution | + +Publicar únicamente los puertos necesarios y limitar sus redes de origen. RabbitMQ Management y PostgreSQL no deben quedar expuestos sin una necesidad operativa y controles de red explícitos. + +## Decisiones previas de infraestructura + +Antes de instalar hay que acordar: + +1. Usuario técnico que ejecutará Podman rootless. +2. Rangos `subuid` y `subgid` asignados a ese usuario. +3. Rutas de NFS y disco local. +4. Política de backup del NFS y PostgreSQL. +5. Puertos y reglas de firewall. +6. Método de arranque automático: systemd de usuario, Quadlet u otro mecanismo administrado. +7. Formato, retención y recogida de logs. + +## Requisitos + +En la VM: + +- `git`; +- `podman`; +- `podman-compose` o un proveedor compatible con `podman compose`; +- `make`; +- `openssl`; +- `ssh-keygen`; +- cliente PostgreSQL para comprobaciones administrativas; +- herramientas SELinux (`semanage` y `restorecon`) si SELinux está activo. + +`crypt4gh` se necesita en el entorno donde se generan o inspeccionan las claves Crypt4GH. En este contexto donde se produzca la encriptaciÓn de los ficheros. Fuera del enterno de la VM. + +Comprobaciones iniciales: + +```bash +podman info +podman ps +podman-compose version || podman compose version +git --version +getenforce 2>/dev/null || true +``` + +No se deben ejecutar los contenedores con `sudo`. Todos los comandos Podman del stack deben ejecutarse con el mismo usuario rootless. + +## Usuario rootless y mapeo de IDs + +Definir un usuario técnico para operar LocalEGA. Puede ser `lega` u otro usuario existente. En esta guía se representa como: + +```text + + +``` + +Si hay que crearlo: + +```bash +sudo useradd -m -s /bin/bash +``` + +Comprobar su identidad en el host: + +```bash +id +``` + +### Subuid y subgid + +El usuario necesita rangos suficientes en `/etc/subuid` y `/etc/subgid`. Sin ellos, los servicios pueden fallar con errores como `setresuid: Invalid argument`. + +Ejecutado como ``: + +```bash +podman unshare cat /proc/self/uid_map +podman unshare cat /proc/self/gid_map +``` + +Ejemplo: + +```text + 0 1003 1 + 1 60000 200000 +``` + +Si los rangos no existen o son insuficientes, corregirlos como administrador. Ejemplo orientativo: + +```bash +sudo usermod \ + --add-subuids 60000-259999 \ + --add-subgids 60000-259999 \ + +``` + +Después es necesario cerrar todas las sesiones del usuario y volver a entrar. `podman system migrate` solo debe ejecutarse si es necesario para aplicar el nuevo mapeo y después de evaluar los demás contenedores rootless del mismo usuario. + +### IDs internos frente a IDs del host + +`LEGA_UID` y `LEGA_GID` son los IDs internos con los que se construye y ejecuta el usuario `lega` en el contenedor. No tienen por qué coincidir con el UID/GID del usuario rootless del host. + +Configuración utilizada en esta guía: + +```env +LEGA_UID=1000 +LEGA_GID=1000 +INBOX_GID=1003 +``` + +Para conocer cómo se representa un ID interno en el host: + +```bash +PROBE=$(mktemp /tmp/localega-idmap.XXXXXX) +podman unshare chown 1000:1000 "$PROBE" +stat -c 'UID:GID del host = %u:%g' "$PROBE" +rm -f "$PROBE" +``` + +Esta traducción es especialmente importante en una implementación en un servidor NFS. Con `root_squash`, el usuario rootless puede no tener permiso para cambiar propietarios; en ese caso, aplicar los UID/GID traducidos desde una cuenta administrativa o desde el servidor NFS. + +## Rutas persistentes + +Rutas recomendadas: + +```bash +REPO_BASE=/opt/containers_apps/localega +REPO_DIR=/opt/containers_apps/localega/LocalEGA +LOCALEGA_DATA_BASE=/impact_data/lega_data/lega +LOCALEGA_BIND_BASE=/srv/containers/bind/localega +LOCALEGA_RUNTIME_BASE=/srv/containers/bind/localega/runtime +LOCALEGA_LOG_DIR=/var/log/local/localega/app +``` + +### NFS: datos de gran tamaño + +En esta configuración se alojan en NFS: + +```text +${LOCALEGA_DATA_BASE}/inbox +${LOCALEGA_DATA_BASE}/staging +${LOCALEGA_DATA_BASE}/vault +${LOCALEGA_DATA_BASE}/vault-db +``` + +El almacenamiento de `vault-db` debe cumplir los requisitos de consistencia y durabilidad de PostgreSQL. Si se utiliza almacenamiento local para PostgreSQL, cambiar esta ruta antes de desplegar. + +### Disco local + +En disco local se alojan: + +```text +${LOCALEGA_BIND_BASE}/etc/nss +${LOCALEGA_BIND_BASE}/etc/authorized_keys +${LOCALEGA_BIND_BASE}/sqlite-boxes +${LOCALEGA_RUNTIME_BASE}/homes +${LOCALEGA_LOG_DIR} +``` + +No se crea `vault.bkp` en esta guía. El Vault debe protegerse mediante la política de backup réplica definida para el almacenamiento. + +## Preparar las rutas y SELinux + +Como administrador: + +```bash +sudo mkdir -p /opt/containers_apps/localega +sudo mkdir -p /impact_data/lega_data/lega +sudo mkdir -p /srv/containers/bind/localega/runtime +sudo mkdir -p /var/log/local/localega/app + +sudo chown -R \ + : \ + /opt/containers_apps/localega \ + /srv/containers/bind/localega \ + /var/log/local/localega +``` + +La propiedad definitiva de los subdirectorios del NFS se configura más adelante según los IDs internos de cada contenedor. No se debe hacer un `chown -R` indiscriminado de un NFS que ya contenga datos. + +### SELinux en disco local + +Si SELinux está activo: + +```bash +sudo semanage fcontext -a \ + -t container_file_t \ + '/srv/containers/bind/localega(/.*)?' + +sudo semanage fcontext -a \ + -t container_file_t \ + '/var/log/local/localega(/.*)?' + +sudo restorecon -Rv \ + /srv/containers/bind/localega \ + /var/log/local/localega +``` + +Para NFS no se debe asumir que `restorecon` puede etiquetar cada fichero. El montaje debe proporcionar un contexto compatible, por ejemplo: + +```text +context=system_u:object_r:container_file_t:s0 +``` + +Configurar el montaje NFS de forma persistente antes de arrancar LocalEGA. + +## Obtener el código + +```bash +cd /opt/containers_apps/localega +git clone --recurse-submodules \ + \ + LocalEGA +cd LocalEGA +``` + +Seleccionar exclusivamente una rama o tag aprobada: + +```bash +git fetch --all --tags +git checkout +git submodule update --init --recursive +git status --short +``` + +`git status --short` debe estar vacío antes de comenzar una instalación de producción. + +## Generar las claves + +Las claves tienen funciones distintas: + +| Fichero | Uso | +|---|---| +| `service.key` | Clave privada utilizada por LocalEGA para procesar ficheros cifrados para el afiliado. | +| `service.key.pub` | Clave pública distribuida a las herramientas o submitters que cifran para este LocalEGA. | +| `master.key` | Clave privada master; debe custodiarse y no distribuirse a submitters. | +| `master.key.pub` | Clave pública utilizada por el flujo de archivado en Vault. | + +Desde `deploy/docker`: + +```bash +cd /opt/containers_apps/localega/LocalEGA/deploy/docker + +ssh-keygen \ + -t ed25519 \ + -f service.key \ + -C 'service_key@LocalEGA' + +ssh-keygen \ + -t ed25519 \ + -f master.key \ + -C 'master_key@LocalEGA' +``` + +Guardar ambas passphrases y las claves privadas en un gestor de secretos. + +El handler monta: + +- `service.key`; +- `master.key.pub`; +- su configuración de aplicación. + +El secreto master requerido por Vault DB se obtiene de la clave privada master. Para evitar que la passphrase quede escrita en el historial: + +```bash +python3 - <<'PY' +from getpass import getpass +import crypt4gh.keys + +passphrase = getpass("Master key passphrase: ") +key = crypt4gh.keys.get_private_key( + "master.key", + lambda: passphrase, +) +print(key.hex()) +PY +``` + +El valor debe configurarse en `pg.conf` como `crypt4gh.master_seckey`. No mostrarlo en logs ni guardarlo en archivos temporales sin protección. + +## Configurar el despliegue + +```bash +cd /opt/containers_apps/localega/LocalEGA/deploy/docker +cp .env.example .env +cp ../../src/vault/pg.conf.sample pg.conf +cp ../../src/vault/pg_hba.conf.sample pg_hba.conf +cp lega.ini.sample lega.ini +``` + +El despliegue centraliza en `.env` las variables soportadas por Compose y los entrypoints. + +Antes de continuar, comprobar qué ficheros espera la versión aprobada: + +```bash +podman compose \ + -f docker-compose.yml \ + -f docker-compose.distribution.yml \ + config >/tmp/localega-compose.yml +``` + +### Variables locales + +```env +APP_NAME=localega + +LOCALEGA_DATA_BASE=/impact_data/lega_data/lega +LOCALEGA_BIND_BASE=/srv/containers/bind/localega +LOCALEGA_LOG_DIR=/var/log/local/localega/app +LOCALEGA_RUNTIME_BASE=/srv/containers/bind/localega/runtime + +INBOX_PORT=8086 +MQ_MANAGEMENT_PORT=15672 +VAULT_DB_PORT=5432 +DISTRIBUTION_PORT=2224 + +LEGA_UID=1000 +LEGA_GID=1000 +INBOX_GID=1003 + +SYNC_INTERVAL_SECONDS=60 +EGA_PRECREATE_HOMES=0 +LEGA_LOG=info +EGA_SSH_BANNER=Affiliated EGA +``` + +Usar `LEGA_LOG=debug` únicamente durante validaciones o troubleshooting controlado. + +### Credenciales y parámetros CEGA + +Obtener por un canal seguro los siguientes parámetros del entorno CEGA: + +```env +CEGA_ENDPOINT= +CEGA_ENDPOINT_CREDS=: +AFFILIATE_NAME= +CEGA_CONNECTION= +``` + +Ejemplo de formato, no de valores: + +```env +CEGA_ENDPOINT=https://nss.example.org +CEGA_ENDPOINT_CREDS=affiliate_user:affiliate_secret +AFFILIATE_NAME=affiliate-name +CEGA_CONNECTION=amqps://affiliate_user:affiliate_secret@rabbitmq.example.org:5677/affiliates +``` + +### RabbitMQ local + +```env +MQ_USER=mqadmin +MQ_PASSWORD= +MQ_PASSWORD_HASH= +MQ_EXCHANGE=cega +MQ_ROUTING_KEY=files.inbox + +LEGA_MQ_CONNECTION=amqp://mqadmin:@mq:5672/%2F +``` + +Generar una contraseña fuerte: + +```bash +openssl rand -base64 32 +``` + +Generar el hash sin incluir la contraseña en el propio script: + +```bash +read -rsp 'MQ password: ' MQ_PASSWORD_INPUT +echo + +MQ_PASSWORD_INPUT="$MQ_PASSWORD_INPUT" python3 - <<'PY' +import base64 +import hashlib +import os + +password = os.environ["MQ_PASSWORD_INPUT"].encode() +salt = os.urandom(4) +digest = hashlib.sha256(salt + password).digest() +print(base64.b64encode(salt + digest).decode()) +PY + +unset MQ_PASSWORD_INPUT +``` + +`MQ_PASSWORD_HASH` debe recalcularse cada vez que cambie `MQ_PASSWORD`. + +### Vault DB, Distribution y service key + +Generar contraseñas diferentes para cada rol: + +```env +LEGA_DB_PASSWORD= +DISTRIBUTION_DB_PASSWORD= +SERVICE_KEY_PASSPHRASE= +``` + +Compose construye internamente `LEGA_DB_CONNECTION` y `FUSE_DB_DSN` a partir de estas contraseñas. No añadir los DSN completos a `.env`. Las contraseñas deben coincidir con las aplicadas posteriormente a los roles PostgreSQL. + +### Configuración PostgreSQL + +Editar `pg.conf` y `pg_hba.conf` según la política de red. `pg_hba.conf` debe limitar los orígenes a las redes y roles estrictamente necesarios. + +Incluir en `pg.conf` el valor de `crypt4gh.master_seckey` generado anteriormente. + + +### Validar la configuración + +Sin mostrar secretos: + +```bash +podman compose \ + -f docker-compose.yml \ + -f docker-compose.distribution.yml \ + config >/tmp/localega-compose-resolved.yml + +echo 'Compose configuration: OK' +``` + +Proteger los ficheros sensibles: + +```bash +chmod 600 .env pg.conf pg_hba.conf service.key master.key +chmod 644 service.key.pub master.key.pub +``` + +## Preparar permisos + +Cargar la configuración sin imprimirla: + +```bash +cd /opt/containers_apps/localega/LocalEGA/deploy/docker +set -a +source .env +set +a +``` + +Crear la estructura: + +```bash +mkdir -p "${LOCALEGA_DATA_BASE}"/{inbox,staging,vault,vault-db} +mkdir -p "${LOCALEGA_BIND_BASE}"/etc/{nss,authorized_keys} +mkdir -p "${LOCALEGA_BIND_BASE}"/sqlite-boxes +mkdir -p "${LOCALEGA_RUNTIME_BASE}"/homes +mkdir -p "${LOCALEGA_LOG_DIR}"/{inbox,mq,handler,vault-db,distribution,nss-sync,inbox-cleaner} +touch "${LOCALEGA_BIND_BASE}"/etc/nss/{users,groups,passwords} +``` + +### Resolver propietarios efectivos + +Antes de aplicar permisos al NFS, calcular cómo representa el host los IDs internos: + +```bash +IDMAP_DIR=$(mktemp -d /tmp/localega-idmap.XXXXXX) + +for spec in \ + 'handler 1000 1000' \ + 'postgres 999 999' \ + 'inbox-group 1000 1003' \ + 'requesters 1000 20000' +do + set -- $spec + label=$1 + uid=$2 + gid=$3 + probe="$IDMAP_DIR/$label" + touch "$probe" + podman unshare chown "$uid:$gid" "$probe" + stat -c "$label -> host %u:%g" "$probe" +done + +rm -rf "$IDMAP_DIR" +``` + +Registrar los resultados de la instalación. No copiar IDs subordinados desde otra VM. + +### Permisos del NFS + +Los siguientes comandos usan IDs internos y funcionan cuando el usuario rootless puede cambiar propietarios: + +```bash +podman unshare chown -R \ + "${LEGA_UID}:${LEGA_GID}" \ + "${LOCALEGA_DATA_BASE}/staging" + +podman unshare find "${LOCALEGA_DATA_BASE}/staging" \ + -type d -exec chmod 2770 {} + +podman unshare find "${LOCALEGA_DATA_BASE}/staging" \ + -type f -exec chmod 660 {} + + +podman unshare chown -R \ + "${LEGA_UID}:20000" \ + "${LOCALEGA_DATA_BASE}/vault" + +podman unshare find "${LOCALEGA_DATA_BASE}/vault" \ + -type d -exec chmod 2750 {} + +podman unshare find "${LOCALEGA_DATA_BASE}/vault" \ + -type f -exec chmod 640 {} + + +podman unshare chown -R \ + 999:999 \ + "${LOCALEGA_DATA_BASE}/vault-db" + +podman unshare find "${LOCALEGA_DATA_BASE}/vault-db" \ + -type d -exec chmod 700 {} + +podman unshare find "${LOCALEGA_DATA_BASE}/vault-db" \ + -type f -exec chmod 600 {} + +``` + +El Inbox requiere un tratamiento adicional: + +- la raíz debe ser accesible por el grupo interno correspondiente; +- cada home debe pertenecer al UID del usuario CEGA dentro del contenedor; +- `.ssh` debe conservar permisos restrictivos; +- no se deben reasignar todos los homes al usuario `lega`. + +Después de que `inbox` pueda resolver los usuarios CEGA, obtener sus IDs con: + +```bash +podman exec inbox getent passwd '' +podman exec inbox id '' +``` + +Aplicar los propietarios traducidos al host mediante `podman unshare` o desde una cuenta con permisos administrativos sobre el NFS. Para cada home: + +```text +propietario = UID interno del usuario EGA +grupo = INBOX_GID +directorios = 2770 o 2775 según política +ficheros = 660 +.ssh = 700 +claves = 600 +``` + +### Permisos de configuración local + +```bash +podman unshare chown -R \ + 999:999 \ + "${LOCALEGA_BIND_BASE}/etc/nss" \ + "${LOCALEGA_BIND_BASE}/etc/authorized_keys" \ + "${LOCALEGA_BIND_BASE}/sqlite-boxes" + +podman unshare chmod 775 \ + "${LOCALEGA_BIND_BASE}/etc/nss" \ + "${LOCALEGA_BIND_BASE}/etc/authorized_keys" + +podman unshare chmod 664 \ + "${LOCALEGA_BIND_BASE}/etc/nss/users" \ + "${LOCALEGA_BIND_BASE}/etc/nss/groups" + +podman unshare chmod 640 \ + "${LOCALEGA_BIND_BASE}/etc/nss/passwords" +``` + +Los logs deben ser escribibles por el usuario del servicio correspondiente. Verificar cada directorio con un contenedor efímero o con el servicio arrancado antes de la validación funcional. + +## Construir las imágenes + +```bash +cd /opt/containers_apps/localega/LocalEGA/deploy/docker + +make images \ + LEGA_UID="${LEGA_UID}" \ + LEGA_GID="${LEGA_GID}" + +podman compose \ + -f docker-compose.yml \ + -f docker-compose.distribution.yml \ + build +``` + +Si la versión aprobada del Makefile utiliza objetivos diferentes, consultar: + +```bash +make help 2>/dev/null || make -n images +``` + +Registrar los IDs y tags de las imágenes desplegadas: + +```bash +podman images --format \ + 'table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Created}}' +``` + +## Inicializar Vault DB + +La inicialización crea el clúster PostgreSQL, los esquemas, roles, tablas, funciones y extensiones que necesita LocalEGA. Es obligatoria en una instalación limpia y no debe repetirse indiscriminadamente sobre una base existente. + +Crear una contraseña de superusuario distinta de las contraseñas de aplicación: + +```bash +read -rsp 'PostgreSQL superuser password: ' PG_SU_PASSWORD_INPUT +echo +umask 077 +printf '%s\n' "$PG_SU_PASSWORD_INPUT" > pg_vault_su_password +unset PG_SU_PASSWORD_INPUT +``` + +Inicializar según el procedimiento de la versión aprobada: + +```bash +make init-vault +``` + +Arrancar `vault-db` y comprobarlo: + +```bash +podman compose up -d vault-db + +podman exec vault-db \ + pg_isready -U postgres -d ega + +podman logs --tail 100 vault-db +``` + +Aplicar las contraseñas de los roles sin escribirlas en el historial. Una opción es entrar de forma interactiva: + +```bash +podman exec -it vault-db \ + psql -U postgres -d ega +``` + +Dentro de `psql`: + +```sql +\password lega +\password distribution +``` + +Las contraseñas introducidas deben coincidir con `LEGA_DB_PASSWORD` y `DISTRIBUTION_DB_PASSWORD`. + +Validación mínima: + +```bash +podman exec vault-db \ + psql -U postgres -d ega -Atc \ + 'SELECT current_database(), current_user, now();' +``` + +## Arrancar LocalEGA + +Arrancar por fases facilita localizar fallos: + +```bash +cd /opt/containers_apps/localega/LocalEGA/deploy/docker + +podman compose up -d vault-db mq inbox +podman compose up -d --no-deps handler +podman compose \ + -f docker-compose.yml \ + -f docker-compose.distribution.yml \ + up -d --no-deps nss-sync distribution +``` + +Resultado esperado: + +```text +mq Up ... docker_internal +vault-db Up ... docker_vault +inbox Up ... docker_internal,docker_external +handler Up ... docker_internal,docker_vault +nss-sync Up ... docker_vault +distribution Up ... docker_vault +``` + +Comprobar: + +```bash +podman ps -a \ + --format 'table {{.Names}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}' +``` + +## Configurar la limpieza del Inbox + +La política recomendada es conservar cada fichero durante 90 días desde que la ingesta se marca como completada. El cleaner solo debe borrar cuando: + +1. existe un registro de ingesta completada; +2. el accession y el fichero archivado existen en Vault; +3. tamaño y metadatos del Inbox coinciden con el registro; +4. ha transcurrido la retención configurada. + +Configuración inicial segura: + +```env +INBOX_RETENTION_DAYS=90 +INBOX_CLEANUP_DRY_RUN=true +INBOX_CLEANUP_INTERVAL_HOURS=24 +INBOX_CLEANUP_BATCH_SIZE=1000 +``` + +Crear el directorio de log con el propietario efectivo del usuario `lega`: + +```bash +mkdir -p "${LOCALEGA_LOG_DIR}/inbox-cleaner" +podman unshare chown \ + "${LEGA_UID}:${LEGA_GID}" \ + "${LOCALEGA_LOG_DIR}/inbox-cleaner" +podman unshare chmod 750 \ + "${LOCALEGA_LOG_DIR}/inbox-cleaner" +``` + +Ejecutar primero una única simulación: + +```bash +podman compose \ + run --rm --no-deps \ + inbox-cleaner --once +``` + +Revisar: + +```bash +podman unshare tail -50 \ + "${LOCALEGA_LOG_DIR}/inbox-cleaner/cleanup.log" +``` + +Mantener `INBOX_CLEANUP_DRY_RUN=true` hasta validar candidatos, permisos, comprobación del Vault y auditoría. El cambio a `false` requiere aprobación operativa explícita. + +Para ejecución periódica: + +```bash +podman compose up -d inbox-cleaner +``` + +## Arranque automático + +Elegir un mecanismo de autoarranque compatible con la administración de la VM. Las opciones habituales son: + +- unidad systemd de usuario; +- Quadlet; +- otro sistema de automatización. + +Para cualquier opción rootless es habitual habilitar linger: + +```bash +sudo loginctl enable-linger +``` + +No se proporciona una unidad universal porque el comportamiento de parada, recreación y dependencia entre servicios debe acordarse. En particular, un `podman compose down` elimina contenedores y redes del proyecto y no debe utilizarse como acción de parada por defecto sin validar su impacto. + +El mecanismo elegido debe: + +- arrancar después de que red y NFS estén disponibles; +- usar siempre el mismo usuario rootless; +- preservar datos y configuración; +- reiniciar servicios fallidos de forma controlada; +- permitir consultar estado y logs; +- no afectar otros stacks Podman de la VM. + +## Validaciones + +### Servicios, IP y DNS + +```bash +podman ps -a \ + --format 'table {{.Names}}\t{{.Status}}\t{{.Networks}}' + +podman inspect mq \ + --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' +podman exec inbox getent hosts mq +podman exec handler getent hosts mq + +podman inspect vault-db \ + --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' +podman exec handler getent hosts vault-db +``` + +Los nombres deben resolver únicamente a las IP actuales de los contenedores en las redes compartidas. + +### RabbitMQ + +```bash +podman exec mq rabbitmq-diagnostics -q ping +podman exec mq rabbitmq-diagnostics check_local_alarms + +podman exec mq rabbitmqctl list_queues \ + name messages messages_ready messages_unacknowledged consumers | + egrep 'from_cega|to_cega|errors|system.errors' +``` + +Resultado esperado: + +- `Ping succeeded`; +- sin alarmas locales; +- `to_cega` con un consumidor; +- `from_cega` con un consumidor; +- colas de error vacías o con mensajes conocidos e investigados. + +### PostgreSQL + +```bash +podman exec vault-db pg_isready -U postgres -d ega + +podman exec vault-db \ + psql -U postgres -d ega -Atc \ + 'SELECT current_database(), current_user, now();' +``` + +### Permisos del Inbox + +Sustituir usuario e IDs por un usuario CEGA real: + +```bash +podman exec --user : inbox sh -c ' + test -r "/ega/inbox/" && echo READABLE + test -w "/ega/inbox/" && echo WRITABLE +' +``` + +### Logs + +```bash +for service in mq vault-db inbox handler nss-sync distribution; do + echo "===== $service =====" + podman logs --tail 100 "$service" +done + +find "${LOCALEGA_LOG_DIR}" \ + -maxdepth 2 -type f -print | sort +``` + +No deben aparecer errores como: + +- `Stale file handle`; +- `Permission denied`; +- resoluciones a IP antiguas; +- `connection refused` persistente; +- errores de descifrado con un fichero cifrado usando la clave pública vigente. + +### Validación funcional + +1. Obtener `service.key.pub` de la instalación vigente por un canal controlado. +2. Crear un fichero de prueba no sensible. +3. Cifrarlo con Crypt4GH usando esa clave pública. +4. Subirlo por SFTP al Inbox. +5. Confirmar el evento en `to_cega`/CEGA. +6. Completar el flujo de ingesta del entorno objetivo. +7. Confirmar el accession en Vault DB y el fichero en Vault. +8. Autorizar el acceso según el procedimiento CEGA/DAC. +9. Confirmar sincronización de identidad y claves. +10. Descargarlo desde `distribution`. + +Un login SFTP y una escritura en Inbox no demuestran por sí solos que la ingesta completa funcione. + +## Operación diaria + +### Estado + +```bash +podman ps -a \ + --format 'table {{.Names}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}' + +podman exec mq rabbitmq-diagnostics -q ping +podman exec vault-db pg_isready -U postgres -d ega +``` + +### Logs + +```bash +podman logs --tail 200 handler +podman logs -f handler +``` + +### Reiniciar un servicio + +Antes de recrearlo, comprobar dependencias, redes y colas: + +```bash +podman compose up -d \ + --force-recreate \ + --no-deps \ + handler +``` + +Después verificar DNS, consumidores y logs. + +### Parar temporalmente + +Usar `podman stop` sobre los servicios concretos cuando se quiera preservar contenedores y redes. Reservar `podman compose down` para operaciones planificadas que requieran retirar el proyecto. + +## Backups + +El backup debe cubrir por separado: + +1. secretos y configuración; +2. PostgreSQL mediante backup lógico o físico compatible; +3. Vault e Inbox según la política del NFS; +4. NSS, authorized keys y SQLite auxiliares; +5. documentación de versiones de código e imágenes. + +### Configuración + +Crear un destino protegido fuera del repositorio: + +```bash +BACKUP_DIR=/ruta_backup_segura/localega_$(date +%Y%m%d_%H%M%S) +umask 077 +mkdir -p "$BACKUP_DIR" + +cp .env pg.conf pg_hba.conf \ + service.key service.key.pub master.key master.key.pub \ + "$BACKUP_DIR/" +``` + +El destino debe estar cifrado, restringido y sujeto a la política de gestión de secretos. + +### PostgreSQL + +```bash +podman exec vault-db \ + pg_dump -U postgres -d ega \ + > "$BACKUP_DIR/vault-db_ega.sql" +``` + +Comprobar que el dump no está vacío y realizar pruebas periódicas de restauración. + +### Datos + +No duplicar automáticamente grandes volúmenes de datos con `rsync`. La réplica, snapshot o backup del NFS debe documentar: + +- frecuencia; +- retención; +- consistencia; +- recuperación; +- responsable; +- prueba de restauración. + +## Actualización y rollback + +Una actualización debe prepararse en una rama/tag aprobada y disponer de: + +- backup verificado; +- inventario de imágenes actuales; +- plan de migración de base de datos; +- ventana de mantenimiento; +- procedimiento de rollback probado. + +Secuencia orientativa: + +```bash +cd /opt/containers_apps/localega/LocalEGA +git fetch --all --tags +git checkout +git submodule update --init --recursive + +cd deploy/docker +podman compose \ + -f docker-compose.yml \ + -f docker-compose.distribution.yml \ + config >/tmp/localega-compose-updated.yml +``` + +Construir y recrear únicamente los servicios afectados. No ejecutar `podman system prune --volumes`, borrar rutas persistentes ni eliminar el almacenamiento rootless como parte de una actualización normal. + +## Troubleshooting + +### El nombre DNS apunta a varias IP antiguas + +Comparar: + +```bash +podman inspect mq \ + --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' +podman exec inbox getent hosts mq +podman exec handler getent hosts mq +``` + +No reiniciar globalmente el DNS rootless sin comprobar qué otros stacks utiliza el mismo usuario. Primero identificar contenedores duplicados, almacenes Podman alternativos y redes antiguas. + +### Podman rootless no puede mapear IDs + +```bash +podman unshare cat /proc/self/uid_map +podman unshare cat /proc/self/gid_map +``` + +Corregir `subuid/subgid` como administrador. No cambiar mapeos con contenedores en ejecución. + +### `Stale file handle` en NFS + +Comprobar primero desde host y contenedor: + +```bash +stat "${LOCALEGA_DATA_BASE}/inbox" +podman exec inbox stat /ega/inbox +findmnt -T "${LOCALEGA_DATA_BASE}/inbox" +``` + +Si el host funciona y el contenedor conserva un handle obsoleto, recrear únicamente el servicio afectado y volver a comprobar propietarios y permisos. Si el host también falla, revisar el montaje y el servidor NFS. + +### Vault DB devuelve `Permission denied` + +```bash +podman logs --tail 200 vault-db +podman top vault-db hpid huser hgroup user group args +findmnt -T "${LOCALEGA_DATA_BASE}/vault-db" +``` + +Comparar el propietario del NFS con el UID/GID subordinado que corresponde al usuario interno `postgres` (`999:999`). No aplicar `chown -R` hasta resolver correctamente la traducción. + +### El handler no consume mensajes + +```bash +podman logs --tail 200 handler +podman exec handler getent hosts mq +podman exec handler getent hosts vault-db +podman exec mq rabbitmqctl list_queues \ + name messages messages_ready messages_unacknowledged consumers +``` + +Validar `LEGA_MQ_CONNECTION`, `LEGA_DB_CONNECTION`, consumidores y DNS. + +### Error decrypting this Crypt4GH file + +Comprobar que el fichero fue cifrado con la `service.key.pub` correspondiente a la `service.key` privada actualmente desplegada. Regenerar claves SSH del Inbox no cambia la clave Crypt4GH, pero reemplazar `service.key` sí invalida los ficheros cifrados con otra clave pública. + +### Distribution no permite login + +```bash +ls -lah "${LOCALEGA_BIND_BASE}/etc/nss" +ls -lah "${LOCALEGA_BIND_BASE}/etc/authorized_keys" +podman logs --tail 200 nss-sync +podman logs --tail 200 distribution +``` + +### Espacio de Podman + +```bash +df -h /srv/containers +podman system df +podman images --filter dangling=true +``` + +`podman image prune -f` elimina imágenes no referenciadas, pero debe revisarse antes en una VM compartida. No usar `--volumes`. + +## Checklist de producción + +- [ ] Usuario rootless y responsables operativos definidos. +- [ ] Rangos `subuid/subgid` suficientes y documentados. +- [ ] Rutas NFS y locales definidas. +- [ ] Montaje NFS y política SELinux comprobados. +- [ ] Política de backup y restauración aprobada. +- [ ] Repo limpio y tag/rama aprobada. +- [ ] `.env` completado sin `CHANGE_ME` ni variables Fake CEGA. +- [ ] Puertos y firewall restringidos. +- [ ] `service.key` y `master.key` generadas y custodiadas. +- [ ] Claves públicas distribuidas por el canal correcto. +- [ ] Secretos fuera de Git y del historial de shell. +- [ ] IDs internos y subordinados documentados. +- [ ] Propietarios y permisos de NFS verificados. +- [ ] Configuración local y logs con permisos correctos. +- [ ] Imágenes construidas y registradas. +- [ ] Vault DB inicializada y roles configurados. +- [ ] Servicios levantados en las redes esperadas. +- [ ] DNS interno consistente con las IP actuales. +- [ ] RabbitMQ sin alarmas y con consumidores activos. +- [ ] PostgreSQL acepta conexiones. +- [ ] Inbox legible y escribible por un usuario real. +- [ ] Flujo funcional completo comprobado. +- [ ] `inbox-cleaner` comprobado primero con `DRY_RUN=true`. +- [ ] Mecanismo de autoarranque aprobado y probado. +- [ ] Logs integrados con el sistema de monitorización. +- [ ] Backup inicial realizado y restauración documentada. From cb37bdc6a907d61d5207a2b53e1996cfe0b1fbfe Mon Sep 17 00:00:00 2001 From: Alejandro Date: Mon, 17 Aug 2026 08:55:29 +0200 Subject: [PATCH 2/3] Clean production Docker deployment configuration --- deploy/docker/.env.example | 22 +-- deploy/docker/README.md | 17 +-- deploy/docker/cega/README.md | 33 +---- deploy/docker/docker-compose.distribution.yml | 2 +- deploy/docker/docker-compose.yml | 38 +---- deploy/docker/docker-compose.yml.sample | 131 ------------------ 6 files changed, 22 insertions(+), 221 deletions(-) delete mode 100644 deploy/docker/docker-compose.yml.sample diff --git a/deploy/docker/.env.example b/deploy/docker/.env.example index ac1cec78..349f54e6 100644 --- a/deploy/docker/.env.example +++ b/deploy/docker/.env.example @@ -1,4 +1,4 @@ -# LocalEGA deployment settings for dcontainers00. +# LocalEGA production deployment settings. # Copy to .env and replace every CHANGE_ME value before starting the stack. APP_NAME=localega @@ -10,41 +10,31 @@ LOCALEGA_RUNTIME_BASE=/srv/containers/bind/localega/runtime INBOX_PORT=8086 MQ_MANAGEMENT_PORT=15672 VAULT_DB_PORT=5432 -CEGA_PORT=8080 -CEGA_MQ_MANAGEMENT_PORT=15670 DISTRIBUTION_PORT=2224 LEGA_UID=1000 LEGA_GID=1000 INBOX_GID=1003 -EGA_SSH_BANNER=Affiliated EGA ciber-isciii +EGA_SSH_BANNER=Affiliated EGA CHANGE_ME_AFFILIATE_NAME -CEGA_ENDPOINT=http://cega:8080 +AFFILIATE_NAME=CHANGE_ME_AFFILIATE_NAME +CEGA_ENDPOINT=https://CHANGE_ME_CEGA_ENDPOINT CEGA_ENDPOINT_CREDS=CHANGE_ME_CEGA_USER:CHANGE_ME_CEGA_PASSWORD -CEGA_CONNECTION=amqp://CHANGE_ME_CEGA_MQ_USER:CHANGE_ME_CEGA_MQ_PASSWORD@cega-mq:5672/%2F +CEGA_CONNECTION=amqps://CHANGE_ME_AFFILIATE_MQ_USER:CHANGE_ME_AFFILIATE_MQ_PASSWORD@CHANGE_ME_CEGA_MQ_HOST:5677/affiliates MQ_USER=CHANGE_ME_MQ_USER MQ_PASSWORD=CHANGE_ME_MQ_PASSWORD MQ_PASSWORD_HASH=CHANGE_ME_RABBITMQ_PASSWORD_HASH MQ_EXCHANGE=cega MQ_ROUTING_KEY=files.inbox -MQ_VERIFY_PEER=no -MQ_VERIFY_HOSTNAME=no -AUTH_VERIFY_PEER=no -AUTH_VERIFY_HOSTNAME=no - -# These must match deploy/docker/cega/mq/definitions.json when using the local CEGA mock. -CEGA_MQ_USER=admin -CEGA_MQ_PASSWORD=CHANGE_ME_CEGA_MQ_PASSWORD LEGA_DB_PASSWORD=CHANGE_ME_LEGA_DB_PASSWORD DISTRIBUTION_DB_PASSWORD=CHANGE_ME_DISTRIBUTION_DB_PASSWORD SERVICE_KEY_PASSPHRASE=CHANGE_ME_SERVICE_KEY_PASSPHRASE -EGAF_COUNTER_START=0 SYNC_INTERVAL_SECONDS=60 EGA_PRECREATE_HOMES=0 -LEGA_LOG=debug +LEGA_LOG=info # Inbox cleanup is safe-by-default. Keep DRY_RUN=true until candidates and # directory permissions have been checked in production. diff --git a/deploy/docker/README.md b/deploy/docker/README.md index cf707687..77baa7bf 100644 --- a/deploy/docker/README.md +++ b/deploy/docker/README.md @@ -10,13 +10,12 @@ It requires: * a master key * a deployment environment file: `.env` * a configuration file for the python handler: `lega.ini` -* a configuration file for docker-compose: `docker-compose.yml` +* a production configuration file for Compose: `docker-compose.yml` * 2 configurations file for postgres: `pg.conf` and `pg_hba.conf` -We assume you have created a local user and a group named `lega`. If not, you can do it with - - groupadd -r lega - useradd -M -g lega lega +Run every Podman command as the same rootless service account. `LEGA_UID` and +`LEGA_GID` configure the `lega` account inside the images and do not need to +match the service account IDs on the host. # Sensitive data @@ -29,9 +28,9 @@ Update `.env` with the deployment-specific values. `docker-compose.yml` reads it cp lega.ini.sample lega.ini -The included message broker uses an administrator account with -`admin:secret` as `username:password`. This is up to you to update it -in your production environment. +Set a dedicated `MQ_USER`, `MQ_PASSWORD` and matching `MQ_PASSWORD_HASH` in +`.env`. Do not use the credentials from the Fake CEGA test fixtures for the +production broker. Generate the service key with: @@ -167,5 +166,3 @@ podman compose up -d inbox-cleaner Review its output with `podman logs inbox-cleaner`. A one-off dry run is also available with `podman compose run --rm --no-deps inbox-cleaner --once`. - -Note that the `mq` component will try to create a federated queue to another RabbitMQ server. In `cega` folder, you will find the necessary components to fake Central EGA, and test your local deployment in isolation. diff --git a/deploy/docker/cega/README.md b/deploy/docker/cega/README.md index d9c03081..265667d2 100644 --- a/deploy/docker/cega/README.md +++ b/deploy/docker/cega/README.md @@ -1,28 +1,9 @@ -# Fake Central EGA +# Fake Central EGA fixtures -We use 2 stubbing services in order to fake the necessary Central EGA components (mostly for local tests or github Actions). - -| Container | Role | -|-----------------:|------| -| `cega` | Sets up a small list of test users, and consumes messages from the broker | -| `cega-mq` | Sets up a RabbitMQ message broker with appropriate accounts, exchanges, queues and bindings | - - -We include 2 dummy users: `jane` and `john`. -> Their password and their ssh-key passphrase are their username. - -You can start the Central EGA (fake) component with: - - # Start the Central EGA broker - docker-compose up -d cega-mq - - # and after a few seconds, start the Central all-in-one service - docker-compose up -d cega - -The Central EGA services are at (and you can update `docker-compose.yml` accordingly) - -| Service | URL | Credentials | Example | -|---------------:|-----|-------------|---------| -| NSS | `http://cega:8080` | `fega:testing` | `curl -u fega:testing http://localhost:8080/username/john` | -| RabbitMQ | `amqp://cega-mq:5672/%2F` | `admin:secret` | `CEGA_CONNECTION=amqp://admin:secret@cega-mq:5672/%2F` | +This directory contains development-only fixtures for emulating Central EGA. +They are not part of the production Compose deployment documented in +`deploy/docker`. +The fixture credentials and data must never be used in a production +environment. A separate, explicit test harness is required to run these +components. diff --git a/deploy/docker/docker-compose.distribution.yml b/deploy/docker/docker-compose.distribution.yml index c98cf231..083c366c 100644 --- a/deploy/docker/docker-compose.distribution.yml +++ b/deploy/docker/docker-compose.distribution.yml @@ -11,7 +11,7 @@ services: - vault environment: FUSE_DB_DSN: postgresql://distribution:${DISTRIBUTION_DB_PASSWORD:?set DISTRIBUTION_DB_PASSWORD in deploy/docker/.env}@vault-db:5432/ega?application_name=EGADistFS - EGA_SSH_BANNER: ${EGA_SSH_BANNER:-Affiliated EGA ciber-isciii} + EGA_SSH_BANNER: ${EGA_SSH_BANNER:-Affiliated EGA} volumes: - ${LOCALEGA_DATA_BASE:-/impact_data/lega_data/lega}/vault:/opt/LocalEGA/vault:ro - ${LOCALEGA_BIND_BASE:-/srv/containers/bind/localega}/etc:/opt/LocalEGA/etc diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 4c83f4d8..4775419d 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -20,11 +20,7 @@ services: MQ_CONNECTION: amqp://${MQ_USER:?set MQ_USER in deploy/docker/.env}:${MQ_PASSWORD:?set MQ_PASSWORD in deploy/docker/.env}@mq:5672/%2F MQ_EXCHANGE: ${MQ_EXCHANGE:-cega} MQ_ROUTING_KEY: ${MQ_ROUTING_KEY:-files.inbox} - MQ_VERIFY_PEER: ${MQ_VERIFY_PEER:-no} - MQ_VERIFY_HOSTNAME: ${MQ_VERIFY_HOSTNAME:-no} - AUTH_VERIFY_PEER: ${AUTH_VERIFY_PEER:-no} - AUTH_VERIFY_HOSTNAME: ${AUTH_VERIFY_HOSTNAME:-no} - EGA_SSH_BANNER: ${EGA_SSH_BANNER:-Affiliated EGA ciber-isciii} + EGA_SSH_BANNER: ${EGA_SSH_BANNER:-Affiliated EGA} ports: - "${INBOX_PORT:-8086}:9000" image: crg/fega-inbox:latest @@ -135,35 +131,3 @@ services: ports: - "${VAULT_DB_PORT:-5432}:5432" entrypoint: ['postgres', '-c', 'config_file=/etc/ega/pg.conf'] - - cega-mq: - hostname: cega-mq - ports: - - "${CEGA_MQ_MANAGEMENT_PORT:-15670}:15672" - image: rabbitmq:3.11.10-management-alpine - container_name: cega-mq - networks: - - internal - volumes: - - ./cega/mq/definitions.json:/etc/rabbitmq/definitions.json:ro - - ./cega/mq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro - - ${LOCALEGA_LOG_DIR:-/var/log/local/localega/app}/cega-mq:/var/log/local/localega/app - - cega: - depends_on: - - cega-mq - hostname: cega - ports: - - "${CEGA_PORT:-8080}:8080" - image: cega - build: ./cega - container_name: cega - networks: - - internal - environment: - EGAF_COUNTER_START: ${EGAF_COUNTER_START:-0} - volumes: - - ./cega/users/users.json:/ega/users.json:ro - - ${LOCALEGA_LOG_DIR:-/var/log/local/localega/app}/cega:/var/log/local/localega/app - entrypoint: ['python', '-m', 'server'] - command: '-d -f 1 amqp://${CEGA_MQ_USER:?set CEGA_MQ_USER in deploy/docker/.env}:${CEGA_MQ_PASSWORD:?set CEGA_MQ_PASSWORD in deploy/docker/.env}@cega-mq:5672/%2F' diff --git a/deploy/docker/docker-compose.yml.sample b/deploy/docker/docker-compose.yml.sample deleted file mode 100644 index 81cecc18..00000000 --- a/deploy/docker/docker-compose.yml.sample +++ /dev/null @@ -1,131 +0,0 @@ -version: '3.7' - -networks: - external: - internal: - vault: - -# volumes: -# mq: -# cega-mq: - -services: - inbox: - hostname: inbox - depends_on: - - mq - container_name: inbox - networks: - - external - - internal - environment: - # - CEGA_ENDPOINT=https://nss.test.ega-archive.org - # - CEGA_ENDPOINT_CREDS=fega-node:fega-secret - - CEGA_ENDPOINT=http://cega:8080 - - CEGA_ENDPOINT_CREDS=fega:testing - - MQ_CONNECTION=amqp://admin:secret@mq:5672/%2F - - MQ_EXCHANGE=cega - - MQ_ROUTING_KEY=files.inbox - - MQ_VERIFY_PEER=no - - MQ_VERIFY_HOSTNAME=no - - AUTH_VERIFY_PEER=no - - AUTH_VERIFY_HOSTNAME=no - # add the relevant certificates if needed (including the volumes injections/mappings) - # - MQ_CA=/etc/ega/CA.cert - # - MQ_CLIENT_CERT=/etc/ega/ssl.cert - # - MQ_CLIENT_KEY=/etc/ega/ssl.key - ports: - - 2222:9000 - image: crg/fega-inbox:latest - volumes: - - ./data/inbox:/ega/inbox - - mq: - environment: - # - CEGA_CONNECTION=amqps://fega-node:fega-secret@rabbitmq.test.ega-archive.org:5671/fega-node - - CEGA_CONNECTION=amqp://admin:secret@cega-mq:5672/%2F - hostname: mq - ports: - - 15672:15672 - image: rabbitmq:3.11.10-management-alpine - container_name: mq - networks: - - internal - # add the relevant certificates if needed (including the volumes injections/mappings) - # environment: - # - MQ_CA=/etc/rabbitmq/CA.cert - # - MQ_SERVER_CERT=/etc/rabbitmq/ssl.cert - # - MQ_SERVER_KEY=/etc/rabbitmq/ssl.key - volumes: - # - mq:/var/lib/rabbitmq - - ../../src/mq/entrypoint.sh:/usr/local/bin/ega-entrypoint.sh - entrypoint: ['/usr/local/bin/ega-entrypoint.sh'] - command: 'rabbitmq-server' - - handler: - depends_on: - - mq - hostname: handler - image: fega/handler:latest - container_name: handler - volumes: - - ./lega.ini:/etc/ega/lega.ini:ro - - ./service.key:/etc/ega/service.seckey:ro - - ./master.key.pub:/etc/ega/master.pubkey:ro - - ./data/inbox:/ega/inbox - - ./data/staging:/ega/staging - - ./data/vault:/ega/vault - networks: - - internal - - vault - command: "/etc/ega/lega.ini" - - vault-db: - hostname: vault - image: fega/vault-db:latest - container_name: vault-db - environment: - - PGDATA=/ega/data - volumes: - - ./data/vault-db:/ega/data - - ./pg.conf:/etc/ega/pg.conf - - ./pg_hba.conf:/etc/ega/pg_hba.conf - # For the distribution users - - /opt/LocalEGA/etc/nss:/etc/ega/nss - - /opt/LocalEGA/etc/authorized_keys:/etc/ega/authorized_keys - - /opt/LocalEGA/etc/sqlite-boxes:/sqlite-boxes - networks: - - vault - user: postgres - ports: - - 5432:5432 - entrypoint: ['postgres', '-c', 'config_file=/etc/ega/pg.conf'] - - cega-mq: - hostname: cega-mq - ports: - - 15670:15672 - image: rabbitmq:3.11.10-management-alpine - container_name: cega-mq - networks: - - internal - volumes: - # - cega-mq:/var/lib/rabbitmq - - ./cega/mq/definitions.json:/etc/rabbitmq/definitions.json - - ./cega/mq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf - - cega: - depends_on: - - cega-mq - hostname: cega - ports: - - 8080:8080 - image: cega - build: ./cega - container_name: cega - networks: - - internal - volumes: - - ./cega/users/users.json:/ega/users.json - entrypoint: ['python', '-m', 'server'] - command: '-d -f 1 amqp://admin:secret@cega-mq:5672/%2F' From 5e4cd87c138a5c4af86aa01547baac48f0ec1ba1 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Mon, 17 Aug 2026 08:55:36 +0200 Subject: [PATCH 3/3] Update existing deployment documentation --- docs/manual_localega_completo.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual_localega_completo.md b/docs/manual_localega_completo.md index 38015442..35b70e67 100644 --- a/docs/manual_localega_completo.md +++ b/docs/manual_localega_completo.md @@ -154,10 +154,10 @@ En este modo: Desde `deploy/docker`: ```bash -cp docker-compose.yml.sample docker-compose.yml +cp .env.example .env cp ../../src/vault/pg.conf.sample pg.conf cp ../../src/vault/pg_hba.conf.sample pg_hba.conf -cp ../../src/handler/conf.ini.sample lega.ini +cp lega.ini.sample lega.ini ``` Genera claves: