REBELION_EN_LA_GRANJA/docs/seguridad.md
s1to 7caa240c2e Ajustar al manual del M1000e, añadir diagramas y docs de operación
Especificaciones tomadas del manual del propietario del gabinete
PowerEdge M1000e (Dell, modelo BMX01, rev. A06, oct. 2019), que corrige
el spec sheet comercial usado hasta ahora.

Hardware:

- Peso máximo 200,5 kg, no 179. Profundidad 75,5 cm
- Seis fuentes y nueve ventiladores obligatorios, se usen 3 blades o 16.
  Toda bahía vacía necesita relleno
- Conector CEI/IEC C20 a 16 A. La fuente de 3.000 W exige 200-240 V
- Irrupción de 55 A por fuente durante 10 ms: un magnetotérmico de curva
  C salta, hace falta curva D
- Temperatura de funcionamiento continuo 10-35 °C
- ECM obligatorio con blades M630 de 120 W o más, o por encima de 30 °C

Red:

- Fabric A (ranuras A1/A2) es la Ethernet integrada de cada blade, así
  que no hacen falta tarjetas intermedias. Fabrics B y C sí las
  exigirían y no se usan
- Pendiente saber si en A1/A2 hay un switch o un módulo de paso a
  través: cambia el montaje de red por completo

Costes recalculados: el suelo fijo del chasis sube de 350 a ~500 W al
contar los nueve ventiladores, los módulos de I/O y las pérdidas de las
seis fuentes. 360 €/mes a 24/7, 59 €/mes por ventanas. Que las fuentes y
los ventiladores sean obligatorios convierte en hecho documentado lo que
antes era estimación: los pilotos parciales en el chasis son el peor
caso posible.

Documentación:

- assets/ con cuatro diagramas SVG propios: arquitectura, chasis, stack
  de software y modos de red
- docs/usabilidad.md: órdenes, flujos de trabajo, problemas conocidos y
  ergonomía del hardware
- Diagramas ASCII del panel frontal, el posterior y la topología de
  fabrics en hardware_m1000e.md
- Eliminada la parte de charla y divulgación, fuera del alcance del repo
2026-08-08 20:04:00 +02:00

8.6 KiB
Raw Blame History

Repaso de seguridad

Revisión del montaje completo — arquitectura, hardware y el código Ansible de 02_device_lab/ansible/. Fecha: 2026-08-08.

Incluye los fallos que introduce el propio código de este proyecto, no solo los del entorno.

Resumen

Hallazgo Severidad Estado
S1 adb sin autenticación + contenedor privilegiado → root del anfitrión Crítico Mitigado a medias
S2 Credenciales por defecto del CMC / iDRAC (root/calvin) Alto Sin verificar
S3 macvlan mete 45 Android en la LAN de producción Alto Por diseño, hay que aislar
S4 host_key_checking = False en ansible.cfg Medio Aceptado, documentado
S5 SSH como root en el inventario de ejemplo Medio Documentado
S6 Imagen de Android por tag mutable Medio Abierto
S7 Sin gestión de secretos Medio Abierto
S8 Estado persistente en /data sin cifrar Medio Abierto
S9 fleet install no verifica el APK Bajo Abierto
S10 Microcódigo antiguo en CPUs de 2011-2016 Bajo Aceptado
S11 Infraestructura de doble uso Contextual Ver legal_ue.md

S1 · adb sin autenticación sobre contenedor privilegiado — crítico

Una cadena de tres eslabones que por separado parecen asumibles:

  1. adb no tiene autenticación cuando escucha en TCP. Quien llega al puerto, entra.
  2. Las imágenes de redroid son userdebug, así que adb root funciona: shell de root dentro del Android.
  3. El contenedor es privileged: true — redroid lo exige para acceder a binder. Un privilegiado ve los devices del anfitrión y puede montar su sistema de ficheros.

Encadenado: cualquiera que alcance el puerto 5555 de un blade acaba siendo root en ese blade, sin exploit, solo con adb connect. Con 45 dispositivos son 45 puertas.

Corregido en parte: el compose ataba adb a 0.0.0.0. Ahora hay redroid_adb_bind_ip, que permite atarlo solo a la interfaz interna del chasis:

blade-02: { ansible_host: 10.0.0.12, redroid_adb_bind_ip: 10.0.0.12 }

Lo que cierra el agujero:

  • Red de laboratorio aislada. VLAN propia para la granja, sin ruta hacia la LAN de casa ni hacia internet salvo lo imprescindible. Es la medida que importa; el resto son parches.
  • Cortafuegos en cada blade (nftables) que solo acepte 5555+ desde la IP del coordinador.
  • Nunca exponer estos puertos a internet. Ni con reenvío de puertos, ni con VPN mal segmentada.

En modo macvlan el problema es peor: adb queda escuchando en la IP de LAN del propio Android, donde redroid_adb_bind_ip no aplica. Ahí la única defensa es la VLAN.


S2 · Credenciales por defecto del CMC y de los iDRAC — alto

Los Dell PowerEdge salen de fábrica con root / calvin en iDRAC, y el CMC del M1000e con las mismas. Es la forma clásica en que se toma uno de estos chasis: no hay que romper nada, se entra.

El M1000e es de 2016 o anterior, así que el firmware de gestión arrastra años de CVEs conocidas y TLS antiguo.

Antes de enchufarlo a nada:

  • Cambiar las credenciales del CMC y de cada uno de los 16 iDRAC, no solo del CMC.
  • Actualizar firmware de CMC e iDRAC hasta donde Dell lo permita para esa generación.
  • VLAN de gestión separada, sin salida a internet. La gestión de un chasis nunca va en la misma red que el resto.
  • Desactivar IPMI sobre LAN si no se usa (cipher 0 es un clásico de acceso sin autenticar).

Esto es independiente de la granja: aplica al hierro desde el momento en que se encienda.


S3 · macvlan expone 45 Android en la LAN — alto

El modo macvlan es el que hace falta para el caso de los dos APKs de oasis_mobile, pero pone cada Android con IP real en la red, cada uno con S1 encima.

  • VLAN dedicada para la granja, con el coordinador como único puente.
  • Reservar el rango de IPs en el DHCP, o habrá colisiones con máquinas reales.
  • No usar la LAN doméstica.

S4 · host_key_checking = False — medio

Lo puse yo en ansible.cfg por comodidad de arranque. El coste: si alguien se hace pasar por un blade, Ansible se conecta igual y le entrega comandos de root y, si se usa, la contraseña de sudo.

Es asumible en el primer aprovisionamiento de una red aislada. Después:

ssh-keyscan -H 10.0.0.11 10.0.0.12 ... >> ~/.ssh/known_hosts

y poner host_key_checking = True.


S5 · SSH como root — medio

inventory/hosts.yml.example trae ansible_user: root. Funciona, pero:

  • Usuario dedicado con sudo en vez de root directo
  • Solo clave, sin contraseña: PasswordAuthentication no
  • PermitRootLogin no en los blades
  • Clave separada para la granja, no la personal

S6 · Imagen de Android por tag mutable — medio

redroid/redroid:13.0.0-latest es un tag que se mueve. Consecuencias reales:

  • Dos blades provisionados con una semana de diferencia acaban con imágenes distintas, y depurar eso es un infierno.
  • Cadena de suministro: si la cuenta del registro se compromete, el siguiente docker compose pull se trae otra cosa. Y entra en 45 contenedores privilegiados.

Fijar por digest:

redroid_image: "redroid/redroid@sha256:<digest>"

Con docker buildx imagetools inspect redroid/redroid:13.0.0-latest se saca el digest actual. Se actualiza a mano cuando se quiera subir de versión, que es justo lo que se quiere.


S7 · Sin gestión de secretos — medio

El inventario de ejemplo menciona ansible_become_password sin montar ansible-vault. Si se pone una contraseña ahí en claro, queda en el disco y en cualquier copia del proyecto.

ansible-vault create group_vars/granja/vault.yml
ansible-playbook site.yml --ask-vault-pass

Mejor aún: sudo sin contraseña para el usuario de despliegue, restringido a los comandos que necesita, y ninguna contraseña en ningún fichero.


S8 · Estado persistente sin cifrar — medio

Cada Android guarda su /data en {{ redroid_base_dir }}/data/device-NN del blade, sin cifrar. Si en las pruebas se entra con cuentas reales — cuentas SSB, credenciales de Gitea, lo que sea — esas credenciales quedan en el disco del blade en claro.

destroy.yml conserva los datos por defecto, a propósito, así que sobreviven a un redespliegue y a un cambio de manos del hardware.

  • Cuentas de prueba desechables, nunca las reales.
  • Cifrado de disco en los blades si van a manejar algo sensible.
  • Al dar de baja un blade: destroy.yml -e confirmar=si -e borrar_datos=si y borrado del disco.

S9 · fleet install no verifica nada — bajo

fleet install app.apk mete el APK en los 45 dispositivos sin comprobar firma ni hash. Como los APK son propios (oasis_mobile), el riesgo es bajo, pero el patrón es malo: un fichero equivocado se propaga a toda la flota de una vez.

Comprobar el hash antes, y a ser posible la firma con apksigner verify --print-certs.


S10 · Microcódigo antiguo — bajo

CPUs de 20112016 con microcódigo sin actualizar: las mitigaciones de Spectre/Meltdown dependen de microcódigo + kernel. En un laboratorio aislado que solo corre código propio, el riesgo es bajo. Subiría si algún día se corre software de terceros no confiable en los Android.

apt install intel-microcode en los blades, y aun así esa generación no recibe todo.


S11 · Infraestructura de doble uso — contextual

Técnicamente, esto es indistinguible de una granja de cuentas: 45 Android automatizados, con control central y despliegue masivo de APKs. Lo que separa un laboratorio de QA de una granja de fraude no es la infraestructura, son tres cosas que no están aquí: SIMs, proxies residenciales y cuentas de plataforma.

Para que siga siendo lo que es:

  • No conectar la granja a proveedores de SIM ni de números por API.
  • No meter proxies residenciales o móviles.
  • Documentar el propósito con evidencia — este repositorio ya lo hace.

El contexto legal está en legal_ue.md. Y recuerda el hallazgo de la investigación: estos Android son detectables como emulador, así que para las plataformas sociales no servirían aunque se quisiera.


Mínimos antes de encender

Por orden:

  1. Cambiar credenciales del CMC y de los 16 iDRAC (S2)
  2. VLAN aislada para granja y gestión, separadas entre sí (S1, S2, S3)
  3. redroid_adb_bind_ip a la IP interna de cada blade (S1)
  4. Claves SSH, sin root, sin contraseñas (S5)
  5. Poblar known_hosts y host_key_checking = True (S4)
  6. Fijar la imagen por digest (S6)

Los tres primeros no son opcionales. Sin ellos, la granja es 45 puertas abiertas a la red.