Ir al contenido

Modelo de seguridad

El router aloja un agente que escucha y nunca abre conexiones hacia fuera, y toda credencial que abre algo distinto del agente se queda en tu máquina. La tabla de abajo es el mapa entero: qué se ejecuta dónde, a qué llega y qué credencial guarda.

Pieza Corre Llega a Credenciales
mikroscope-agent en un contenedor scratch dentro del router sirve HTTP solo en la dirección de la veth; ninguna conexión saliente no presenta ninguna; un token bearer opcional que exige
mikroscope doctor, install, upgrade, uninstall, status tu máquina, cuando los ejecutas el router por tu propio ssh de administrador; install, upgrade y status además sondean el /healthz del agente, y doctor lee /healthz y después el anillo del agente, como mucho sus 10 000 muestras más recientes; uninstall --targets dashboard o data llega además a tu Grafana y a los almacenes tu clave ssh; doctor presenta además el token del agente si hay uno; GRAFANA_TOKEN y las credenciales de los destinos para esos objetivos
mikroscope plan, install --dry-run, upgrade --dry-run tu máquina nada: construyen la imagen e imprimen el listado sin conectarse al router ninguna, salvo que plan --rsc reciba un token (abajo)
mikroscope record, forward tu máquina el agente por HTTP; la API binaria del router para la capa de la API de forward, el transporte relay y record --log-markers el token del agente si hay uno; un usuario de la API dedicado y de solo lectura; GRAFANA_TOKEN con --grafana
mikroscope mark tu máquina los ficheros locales de la grabación; la API binaria del router solo con --log-markers; nunca el agente el usuario de la API, solo con --log-markers
destinos tu máquina, dentro de forward sirven /metrics para tu Prometheus; envían a InfluxDB y a los demás destinos que indiques sus tokens, en tu entorno
mikroscope dashboards publish, import, check tu máquina tu Grafana; publish crea o corrige allí las fuentes de datos y la carpeta GRAFANA_TOKEN, en tu entorno; publish además las credenciales de los destinos que copia en las fuentes de datos

plan, install --dry-run y upgrade --dry-run nunca llegan al router, así que tampoco hacen las comprobaciones de propiedad; esas solo se hacen en un install real.

La herramienta no informa de nada a ningún sitio. No hay comprobación de actualizaciones. En el código, el único código de red del agente es su servidor HTTP. Las conexiones salientes viven todas en la CLI — los destinos (HTTP, TCP o UDP), el cliente de Grafana, el cliente de la API de RouterOS, el transporte directo, la sonda de /healthz y la lectura del anillo de doctor, las tres últimas por HTTP sin cifrar — y cada una va solo a una dirección que tú le diste o, para el agente, a la .2 de --subnet (172.30.10.2 salvo que la cambies).

La exposición Prometheus del propio colector, forward --prom <dirección>, escucha en la dirección que le pases y sirve /metrics sin autenticación. Enlázala a una dirección a la que solo llegue tu Prometheus.

Por la API binaria, /container/print devuelve todas las propiedades de todos los contenedores, cmd y envlist incluidas, a un usuario con solo read,api (verificado). Si un usuario así puede leer también los valores de las entradas de la envlist, en /container/envs, está sin probar. El diseño supone que sí: lo que haya en una envlist se trata como legible por cualquier usuario read de ese router, no solo por los administradores.

Por eso el agente no tiene destino push: un token de destino en el router lo podría leer cualquier usuario read. Si algún día llega el push, será agente → colector con el mismo NDJSON, nunca agente → InfluxDB.

Lo que install sí pone en la envlist <name>-env es configuración, y nada que abra otra cosa:

Las entradas que install escribe en la envlist del agente
ClaveSe escribeViene deContiene
MIKROSCOPE_TAGsiempre--namela marca de propiedad mikroscope:<name> (managed by mikroscope), que se escribe la primera y se borra la última; el agente la ignora
RATE_HZsiempre--rate, por defecto 10, 1–100la cadencia del muestreador, en Hz
BUFFER_Ssiempre--buffer, por defecto 60, 10–3600la longitud del anillo, en segundos
PORTsiempre--port, por defecto 9123, 1–65535el puerto HTTP del agente
ADDRsiempre--subnetla dirección del agente, la .2 de la /30; el agente solo escucha ahí
MEM_LIMIT_MBsiempre--mem-limit-mb, 8–1024el límite blando de memoria de Go del agente, en MiB; se deriva del anillo (cadencia × búfer × línea, × 2,5, con un mínimo de 16 MiB y un máximo de tres cuartos de --memory-max mientras en él aún quepa el anillo) salvo que lo fije --mem-limit-mb
FLOOR_HZsolo cuando es mayor que 0--floor-hz, por defecto 0, 0–1000una sola cadencia para todas las fuentes de nivel, en Hz
CAPTURE_MBsiempre--capture-mb, por defecto 4, 0–256el presupuesto de capturas por disparo, en MiB; 0 las desactiva
TRIGGERSsolo cuando se da--triggerslas condiciones de disparo; sin ella, el agente usa su conjunto por defecto
TOKENsolo cuando se da--tokenel token bearer que exige el agente, de --token o MIKROSCOPE_TOKEN, con o sin --expose

La última fila es el único secreto que sí vive en el router. Se escribe siempre que se dé --token o MIKROSCOPE_TOKEN, con o sin --expose, y como el resto de la envlist se trata como legible por cualquier usuario read. Abre las rutas HTTP del propio agente y nada más. plan y --dry-run lo imprimen como value="(token)", la línea de opciones como token=(set), y la línea de arranque del agente en el log del router como token=true.

plan --rsc es la excepción a ese enmascarado. Escribe la instalación como un script de RouterOS para ejecutarlo en el propio router, así que la línea de la envlist tiene que llevar el token real; el propio script lo dice en su cabecera. Un .rsc generado con un token dentro es una credencial: Salvaguardas del instalador explica cómo tratarlo.

En tu máquina, las credenciales que abren algo distinto del agente se leen solo del entorno, nunca de una opción, con una excepción: el DSN de PostgreSQL, abajo. El código da el motivo: una opción se ve en ps y en el historial de la shell.

  • La contraseña del usuario de la API: MIKROSCOPE_API_PASSWORD. La dirección y el usuario vienen de --api y --api-user, o de MIKROSCOPE_API_ADDR y MIKROSCOPE_API_USER.
  • Credenciales de los destinos: MIKROSCOPE_INFLUX_TOKEN, MIKROSCOPE_LOKI_TOKEN, MIKROSCOPE_OTLP_TOKEN, MIKROSCOPE_ELASTIC_AUTH, MIKROSCOPE_TELEGRAF_TOKEN.
  • PostgreSQL (--postgres, o MIKROSCOPE_POSTGRES_DSN): el DSN es una opción, así que deja la contraseña fuera de él y que el driver la lea de PGPASSWORD o de ~/.pgpass, como hace psql. Una contraseña escrita en un DSN pasado como opción se ve en ps, y venga de donde venga el DSN, forward --grafana y dashboards publish copian la contraseña escrita en él en la fuente de datos de Grafana que crean. Una contraseña que solo está en el entorno o en el fichero de contraseñas no se copia.
  • forward --grafana y dashboards publish copian también el token de InfluxDB (MIKROSCOPE_INFLUX_TOKEN, que puede escribir) y MIKROSCOPE_ELASTIC_AUTH en las fuentes de datos que crean. Para dar a Grafana una credencial de solo lectura, crea tú la fuente de datos y pasa --grafana-datasource-uid.
  • Grafana: GRAFANA_TOKEN.

El token del agente es la excepción: tiene una opción --token además de MIKROSCOPE_TOKEN. El mismo razonamiento vale para él, así que prefiere la variable.

La CLI no lee .env por su cuenta. Exporta las variables a la shell que la ejecuta, por ejemplo con set -a; . ./.env; set +a.

El contenedor ejecuta una imagen, y la vía que la pone ahí decide en qué estás confiando.

  • install con una cadena de herramientas de Go y un checkout construye la imagen en tu máquina a partir del código que tienes delante y la sube por tu propia sesión ssh. Confías en tu propio árbol.
  • install --agent-tar <fichero> sube el tar que publica la release, por esa misma sesión ssh. La CLI comprueba que el tar es una imagen del agente de mikroscope de la arquitectura que nombra --arch antes de enviarlo; comprobar que es el fichero que publicó la release te toca a ti, contra checksums.txt.
  • install --remote-image <referencia> no sube nada: es el propio router quien descarga la imagen del registro que nombra la referencia, que mikroscope escribe en remote-image= con su host, registry-1.docker.io para Docker Hub; el ajuste global /container/config registry-url ni hace falta ni se escribe. Confías en ese registro y en el camino del router hasta él, y mikroscope no verifica nada de lo que llega. /container/config guarda además un único usuario y contraseña de registro para todo el equipo, y un login de Docker Hub enviado a GHCR hace fallar la descarga con auth error (probado); Salvaguardas del instalador explica qué supone y qué comprueba doctor.
  • plan --rsc escribe esas mismas órdenes como un script de RouterOS para pegarlo o hacerle /import; la imagen sigue teniendo que llegar por una de las dos vías anteriores que no necesitan una subida desde la CLI.

install crea un contenedor con estos ajustes, todos impresos por plan antes de escribir nada (dónde se verificaron):

  • privileged=yes por defecto, --privileged=false para renunciar a ello. El ajuste necesita RouterOS 7.24 o posterior, cuyo registro de cambios añadió el modo privilegiado para contenedores. Quita el espacio de nombres de usuario del contenedor (verificado), que es lo que hace legibles el log del kernel, /proc/slabinfo, /proc/pagetypeinfo y los contadores ECC de la MTD. No quita el espacio de nombres de red ni el de PID: ni contadores de interfaz, ni la tabla conntrack del router, ni vista de los procesos de RouterOS. Modo privilegiado tiene lo que hace legible.
  • memory-max=64M (--memory-max), aplicado como límite cgroup del contenedor, con el límite blando de Go del agente (--mem-limit-mb) dentro de él. Si no pasas un número, se deriva del anillo (cadencia × búfer × línea, × 2,5, con un mínimo de 16 MiB y un máximo de tres cuartos de memory-max mientras en él aún quepa el anillo): 16 MiB con los valores por defecto.
  • restart-policy=on-failure, limitado a cinco reintentos separados diez segundos, para que una imagen rota no pueda entrar en bucle al arrancar.
  • start-on-boot=yes, o no con --ephemeral, cuya raíz vive en el disco tmpfs y no sobrevive a un reinicio. Que la instalación sobreviva a un reinicio con yes está sin probar.
  • logging=yes, para que las líneas de ciclo de vida del agente lleguen al log del router.
  • ignore-remote-image-change=yes: con el valor por defecto, RouterOS vigila la imagen y, en cuanto se borra el tar, detiene y elimina el contenedor y lo vuelve a extraer minutos después (verificado). install borra el tar justo después de la extracción, y por eso fija este ajuste.
  • Raíz e imagen en el disco que elegiste con --disk: la flash interna por defecto.
  • Ningún bind mount. install no monta ninguna ruta del anfitrión dentro del contenedor.

El agente lee /proc, /sys (/sys/fs/cgroup para su propia contabilidad, /sys/class/thermal y /sys/class/mtd para el equipo) y — con privileged — /dev/kmsg y los contadores de rendimiento del hardware. No escribe nada en su raíz durante la ejecución: el anillo y las capturas por disparo se guardan en memoria. Atrapa SIGTERM, porque RouterOS mata en el acto a un contenedor que no lo hace.

El último ajuste de la lista es deliberado. Montar /proc y /sys del anfitrión en un contenedor privilegiado no añade nada, porque los espacios de nombres aguantan, pero el / del anfitrión expone el sistema de ficheros de la flash de RouterOS, configuración y secretos incluidos (Montajes del host). mikroscope no hace esto, y un contenedor que construyas tú tampoco debería.

Informa de una vulnerabilidad en privado, nunca con sus detalles en un issue ni en una discusión públicos: abre la pestaña Security del repositorio y elige Report a vulnerability. GitHub abre entonces un aviso privado que solo ve el mantenedor. Si ese botón no aparece, abre una discusión en General que pida un canal privado y no diga nada más del problema, y espera ahí una respuesta que te lo indique; los issues pasan por formularios que piden los detalles, así que un issue no puede quedarse tan vacío. Incluye la versión (mikroscope version, y la del agente, de la línea agent: de mikroscope status, si es distinta), la versión de RouterOS y la placa, lo que gana un atacante y la forma más corta de reproducirlo. Si una prueba de concepto necesita una credencial, una dirección de router o un export, no lo envíes: descríbelo.

La política en sí es SECURITY.md. Promete un acuse de recibo en una semana y, una vez confirmado el informe, una corrección publicada antes que el aviso; quien quiera que se le mencione aparece en el aviso, y quien no, no se nombra. Solo se da soporte a la última versión, porque una corrección sale como una etiqueta nueva y no como un parche sobre una anterior. También dice qué merece informarse: todo lo que rompa la separación que describe esta página, como que algo distinto del colector configurado llegue al agente o que una credencial aparezca donde no debe. Los requisitos que impone RouterOS, y que el token del agente sea legible para cualquier usuario read, son decisiones documentadas, no vulnerabilidades.