mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 21:03:17 +00:00
- Fase 0: scripts de aprovisionamiento (db/provision/) para roles, dos bases de datos separadas (panels_platform / panels_product con esquemas iam+core) y ACLs de Redis por modulo, con verificacion automatizada de aislamiento (verify-isolation.sh) y setup local reproducible (dev-local.sh). - Fase 1: changelogs de Liquibase reescritos para Postgres (db/platform, db/iam, db/core reemplazan db/app + los changesets SQLite de platform). Baseline como estado final (no replay literal), tipos traducidos (IDENTITY, TIMESTAMPTZ/DATE, NUMERIC, BOOLEAN, CITEXT), contexts dev vs. schema/catalogos, RLS por tenant_id como defensa en profundidad, uploaded_by/created_by como snapshot desnormalizado (sin FK hacia iam). - Migraciones ya no corren en el arranque de la API: paso explicito de deploy via db/update.sh con credenciales _owner. Verificado end-to-end contra Postgres 16 + Redis local. Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
64 lines
2.8 KiB
Bash
Executable file
64 lines
2.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# PANELS · Redis · Fase 0 (usuarios ACL por módulo)
|
|
#
|
|
# Crea dos usuarios ACL (Redis 6+) con acceso restringido por patrón de
|
|
# llave: panels_iam_redis (~iam:*) y panels_core_redis (~core:*). Un
|
|
# prefijo de llave por sí solo NO aísla nada — cualquier cliente con la
|
|
# misma contraseña puede escanear todo el keyspace; el aislamiento real
|
|
# lo da el ACL server-side, no la convención de nombres.
|
|
#
|
|
# Uso:
|
|
# REDIS_ADMIN_URL="redis://:admin-password@host:6379" \
|
|
# IAM_REDIS_PASSWORD="$(openssl rand -base64 32)" \
|
|
# CORE_REDIS_PASSWORD="$(openssl rand -base64 32)" \
|
|
# ./05-redis-acl.sh
|
|
set -euo pipefail
|
|
|
|
: "${REDIS_ADMIN_URL:?Define REDIS_ADMIN_URL (redis://[:password@]host:port)}"
|
|
: "${IAM_REDIS_PASSWORD:?Define IAM_REDIS_PASSWORD}"
|
|
: "${CORE_REDIS_PASSWORD:?Define CORE_REDIS_PASSWORD}"
|
|
|
|
# Categorías necesarias para sesiones (hash/string + TTL) y cache
|
|
# (string/hash/set): keyspace cubre DEL/EXPIRE/EXISTS/TTL/SCAN (el patrón de
|
|
# llave sigue acotando el alcance real). Sin @scripting (no se usa Lua/EVAL,
|
|
# menor superficie de ataque) ni @admin/@dangerous.
|
|
ACL_COMMANDS="-@all +@read +@write +@keyspace +@string +@hash +@set +@sortedset +@connection"
|
|
|
|
# Importante: "reset" debe ir PRIMERO (deja al usuario en blanco); si va
|
|
# después de "on >password" borra la contraseña que se acaba de fijar.
|
|
echo "Creando usuario panels_iam_redis (~iam:*)..."
|
|
redis-cli -u "$REDIS_ADMIN_URL" ACL SETUSER panels_iam_redis \
|
|
reset \
|
|
on ">${IAM_REDIS_PASSWORD}" \
|
|
'~iam:*' '&iam:*' \
|
|
$ACL_COMMANDS
|
|
|
|
echo "Creando usuario panels_core_redis (~core:*)..."
|
|
redis-cli -u "$REDIS_ADMIN_URL" ACL SETUSER panels_core_redis \
|
|
reset \
|
|
on ">${CORE_REDIS_PASSWORD}" \
|
|
'~core:*' '&core:*' \
|
|
$ACL_COMMANDS
|
|
|
|
redis-cli -u "$REDIS_ADMIN_URL" ACL SAVE >/dev/null 2>&1 || {
|
|
echo "Aviso: ACL SAVE falló (normal si no hay aclfile configurado; revisar persistencia de ACLs por separado)."
|
|
}
|
|
|
|
HOST_PORT=$(echo "$REDIS_ADMIN_URL" | sed -E 's#^redis://##; s#^[^@]*@##')
|
|
|
|
echo "Verificando aislamiento (se espera NOPERM al cruzar de modulo)..."
|
|
IAM_PROBE=$(redis-cli -u "redis://panels_iam_redis:${IAM_REDIS_PASSWORD}@${HOST_PORT}" GET core:probe 2>&1 || true)
|
|
if echo "$IAM_PROBE" | grep -qi "NOPERM"; then
|
|
echo "OK: panels_iam_redis no puede leer llaves core:*"
|
|
else
|
|
echo "ADVERTENCIA: no se confirmó NOPERM al probar panels_iam_redis -> core:*. Salida: $IAM_PROBE"
|
|
fi
|
|
|
|
CORE_PROBE=$(redis-cli -u "redis://panels_core_redis:${CORE_REDIS_PASSWORD}@${HOST_PORT}" GET iam:probe 2>&1 || true)
|
|
if echo "$CORE_PROBE" | grep -qi "NOPERM"; then
|
|
echo "OK: panels_core_redis no puede leer llaves iam:*"
|
|
else
|
|
echo "ADVERTENCIA: no se confirmó NOPERM al probar panels_core_redis -> iam:*. Salida: $CORE_PROBE"
|
|
fi
|
|
|
|
echo "Listo. Guarda IAM_REDIS_PASSWORD/CORE_REDIS_PASSWORD como secrets (REDIS_URL_IAM/REDIS_URL_CORE)."
|