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.
Qué se ejecuta dónde
Sección titulada «Qué se ejecuta dónde»| 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 |
Desliza en horizontal para ver todas las columnas
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.
Credenciales en el router
Sección titulada «Credenciales en el router»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:
| Clave | Se escribe | Viene de | Contiene |
|---|---|---|---|
MIKROSCOPE_TAG | siempre | --name | la marca de propiedad mikroscope:<name> (managed by mikroscope), que se escribe la primera y se borra la última; el agente la ignora |
RATE_HZ | siempre | --rate, por defecto 10, 1–100 | la cadencia del muestreador, en Hz |
BUFFER_S | siempre | --buffer, por defecto 60, 10–3600 | la longitud del anillo, en segundos |
PORT | siempre | --port, por defecto 9123, 1–65535 | el puerto HTTP del agente |
ADDR | siempre | --subnet | la dirección del agente, la .2 de la /30; el agente solo escucha ahí |
MEM_LIMIT_MB | siempre | --mem-limit-mb, 8–1024 | el 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_HZ | solo cuando es mayor que 0 | --floor-hz, por defecto 0, 0–1000 | una sola cadencia para todas las fuentes de nivel, en Hz |
CAPTURE_MB | siempre | --capture-mb, por defecto 4, 0–256 | el presupuesto de capturas por disparo, en MiB; 0 las desactiva |
TRIGGERS | solo cuando se da | --triggers | las condiciones de disparo; sin ella, el agente usa su conjunto por defecto |
TOKEN | solo cuando se da | --token | el token bearer que exige el agente, de --token o MIKROSCOPE_TOKEN, con o sin --expose |
Desliza en horizontal para ver todas las columnas
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.
Credenciales del colector
Sección titulada «Credenciales del colector»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--apiy--api-user, o deMIKROSCOPE_API_ADDRyMIKROSCOPE_API_USER. - Credenciales de los destinos:
MIKROSCOPE_INFLUX_TOKEN,MIKROSCOPE_LOKI_TOKEN,MIKROSCOPE_OTLP_TOKEN,MIKROSCOPE_ELASTIC_AUTH,MIKROSCOPE_.TELEGRAF_ TOKEN - PostgreSQL (
--postgres, oMIKROSCOPE_POSTGRES_DSN): el DSN es una opción, así que deja la contraseña fuera de él y que el driver la lea dePGPASSWORDo de~/.pgpass, como hace psql. Una contraseña escrita en un DSN pasado como opción se ve enps, y venga de donde venga el DSN,forward --grafanaydashboards publishcopian 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 --grafanaydashboards publishcopian también el token de InfluxDB (MIKROSCOPE_INFLUX_TOKEN, que puede escribir) yMIKROSCOPE_ELASTIC_AUTHen 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.
Origen de la imagen del agente
Sección titulada «Origen de la imagen del agente»El contenedor ejecuta una imagen, y la vía que la pone ahí decide en qué estás confiando.
installcon 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--archantes de enviarlo; comprobar que es el fichero que publicó la release te toca a ti, contrachecksums.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 enremote-image=con su host,registry-1.docker.iopara Docker Hub; el ajuste global/container/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.config registry-url /container/configguarda 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 conauth error(probado); Salvaguardas del instalador explica qué supone y qué compruebadoctor.plan --rscescribe 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.
Ajustes del contenedor
Sección titulada «Ajustes del contenedor»install crea un contenedor con estos ajustes, todos impresos por plan antes de escribir
nada (dónde se verificaron):
privileged=yespor defecto,--privileged=falsepara 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/pagetypeinfoy 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 dememory-maxmientras 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, onocon--ephemeral, cuya raíz vive en el disco tmpfs y no sobrevive a un reinicio. Que la instalación sobreviva a un reinicio conyesestá 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).installborra 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.
installno 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.
Informar de una vulnerabilidad
Sección titulada «Informar de una vulnerabilidad»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.