Cómo usar AppArmor en Linux y detectar cambios en scripts

Última actualización: 17/12/2025
Autor: Isaac
  • AppArmor implementa un control de acceso obligatorio basado en perfiles por ruta, más sencillo de administrar que SELinux y muy útil para confinar servicios y scripts.
  • Los perfiles se almacenan en /etc/apparmor.d, se gestionan con utilidades como aa-status, aa-enforce, aa-complain o apparmor_parser y pueden crearse de forma guiada con aa-genprof y aa-logprof.
  • Combinando AppArmor con scripts de comprobación de hashes (stat, find, du, sha1sum) se pueden detectar cambios en código y directorios críticos, incluso excluyendo rutas concretas.
  • En entornos de nube, una configuración correcta de kernel, cloud-init y AppArmor evita muchos problemas de aprovisionamiento y facilita auditar comportamientos anómalos de procesos.

Seguridad con AppArmor en Linux

Si trabajas con GNU/Linux y te preocupa la seguridad de tus scripts y servicios, tarde o temprano te toparás con AppArmor como pieza clave para controlar qué puede hacer cada proceso. No solo sirve para endurecer el sistema: bien usado, también te ayuda a enterarte cuando algo cambia donde no debería, por ejemplo en el código de un script delicado.

En las próximas líneas vamos a ver, con bastante calma pero al grano, qué es AppArmor, cómo funciona frente a otros sistemas como SELinux, cómo se activa y se gestiona en las distros más comunes (especialmente Debian y Ubuntu), cómo crear y ajustar perfiles propios y, por último, cómo aprovechar todo esto junto con pequeñas técnicas en shell para detectar cambios en el código de scripts o directorios en Linux sin necesidad de montar una vigilancia en tiempo real.

Qué es AppArmor y por qué importa para tus scripts

AppArmor (Application Armor) es un mecanismo de control de acceso obligatorio, o MAC, integrado en el kernel Linux a través de la interfaz Linux Security Modules (LSM). En lugar de confiar solo en los permisos clásicos de usuario/grupo (el modelo DAC de toda la vida), añade una capa extra que define de forma estricta qué puede hacer cada programa.

En la práctica, el núcleo consulta a AppArmor antes de ejecutar ciertas llamadas al sistema (abrir ficheros, crear sockets, ejecutar otros binarios, usar determinadas capacidades, etc.) para saber si el proceso que hace la petición está autorizado según su perfil de seguridad. Si la regla lo permite, se ejecuta; si no, se bloquea o se registra, según el modo.

La unidad básica en AppArmor es el perfil: un conjunto de reglas que se asocia a un ejecutable identificado por su ruta absoluta, por ejemplo /usr/sbin/sshd o /bin/ping. Al contrario que en SELinux, las reglas de un perfil se aplican igual a todos los usuarios que ejecutan ese binario; los permisos Unix tradicionales siguen existiendo, pero AppArmor va por encima, delimitando aún más el alcance.

Los perfiles se almacenan como ficheros de texto plano en /etc/apparmor.d/ y se cargan en el kernel normalmente durante el arranque. Cada perfil se puede ejecutar en modo estricto (enforce), donde las violaciones se bloquean y se registran, o en modo relajado (complain), donde se permiten pero quedan anotadas en los logs para revisarlas después.

Históricamente, AppArmor nació impulsado por Novell en 2005 y se utilizaba sobre todo en SUSE y openSUSE, pero Canonical lo llevó al mainline del kernel a partir de la versión 2.6.36. Hoy en día lo integran por defecto muchas distros como Ubuntu y sus derivadas o Debian (activado desde Debian 10), mientras que otras como Fedora o RHEL siguen apostando por SELinux como solución MAC principal.

DAC, MAC, AppArmor y SELinux: en qué se diferencian

Para entender qué aporta AppArmor, conviene separar dos modelos de permisos que conviven en Linux: DAC (Discretionary Access Control) y MAC (Mandatory Access Control). El DAC es el que conoces de siempre: propietario, grupo, otros, bits rwx, ACLs, etc. Cada usuario puede gestionar los permisos de sus ficheros dentro de ciertos límites.

El modelo MAC, por su parte, no es discrecional: las decisiones de acceso se basan en políticas globales definidas por el administrador y aplicadas por el sistema, independientemente de quién sea el dueño de un archivo. Aquí es donde entran AppArmor y SELinux, ambos como dos implementaciones distintas de MAC bajo la interfaz LSM, pero con filosofías de uso muy diferentes.

SELinux usa etiquetas de seguridad (contexts) asociadas a procesos, ficheros, sockets, etc., y decide en base a combinaciones de etiquetas más roles, tipos y demás jerga. Esto le da un control extremadamente granular, pero también una complejidad alta tanto de administración como de auditoría. AppArmor, en cambio, se basa en rutas de ficheros: un perfil se asocia a una ruta concreta del ejecutable y describe qué recursos puede usar dicho binario.

Esto hace que los perfiles de AppArmor suelan ser más fáciles de leer, escribir y mantener para un administrador medio. A cambio, se renuncia a parte de la flexibilidad de SELinux, que permite controlar más tipos de operaciones y escenarios. En muchas distribuciones, AppArmor se ha convertido en una opción muy práctica para endurecer servicios habituales sin volverse loco con la sintaxis.

En el contexto de scripts y automatizaciones, AppArmor te permite limitar qué puede hacer un determinado script (por ejemplo, qué directorios puede leer o modificar, o si puede abrir conexiones de red), y gracias a su modo complain también detectar accesos inesperados antes incluso de bloquearlos.

Estados, perfiles y monitorización de AppArmor

Antes de usar AppArmor para proteger nada, hay que comprobar si está realmente operativo en el sistema. En distros como Ubuntu o Debian actuales, suele venir integrado, pero no siempre todos los perfiles están activos ni todos están en modo enforce, así que conviene echarle un ojo.

Para verificar de forma rápida si AppArmor está habilitado, puedes usar:

sudo aa-enabled

Este comando responde básicamente con un «Yes» si el módulo está activo o un «No» en caso contrario (por ejemplo, si el kernel no se arrancó con soporte AppArmor o el servicio no está cargado).

Si quieres ver el detalle de todos los perfiles cargados y su estado, el comando clave es:

  Tutorial del comando journalctl: guía completa y práctica

sudo aa-status

La salida de aa-status muestra, entre otras cosas, el número de perfiles cargados, cuántos están en modo enforce, cuántos en modo complain y el listado de rutas asociadas a cada uno. Esta información es muy útil para tener una foto rápida del nivel de protección real que aporta AppArmor en tu máquina.

Por ejemplo, podrías ver algo similar a:

apparmor module is loaded.
46 profiles are loaded.
44 profiles are in enforce mode.
/snap/bin/evince
/snap/bin/evince/previewer
...
2 profiles are in complain mode.
/snap.code.code
...

Cuantos más perfiles se encuentren en modo enforce, más estricta será la política global. Los perfiles en modo complain no bloquean operaciones, pero registran cada violación, algo muy valioso para ajustar perfiles sin romper servicios o para auditar qué está intentando hacer una aplicación.

Instalación y activación de AppArmor en Debian y Ubuntu

En Debian y Ubuntu actuales el soporte de AppArmor ya viene en el kernel estándar, de modo que activar el sistema es cuestión de instalar los paquetes necesarios y asegurarse de que el módulo arranca en el boot del sistema.

apt -y install apparmor apparmor-profiles apparmor-utils

El paquete apparmor-utils aporta las herramientas de línea de comandos para comprobar estados (aa-status), cambiar modos de perfiles (aa-enforce, aa-complain), crear nuevos perfiles (aa-genprof), revisar logs (aa-logprof), etc.

En algunos entornos, además, puede ser necesario forzar que el kernel arranque con AppArmor como sistema LSM activo. Una forma típica en Ubuntu es añadir los parámetros al GRUB con:

perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub
update-grub
reboot

Tras el reinicio, AppArmor debería estar cargado, algo que puedes confirmar con aa-status o apparmor_status (este último es un nombre alternativo muy extendido).

Si necesitas ampliar la colección de perfiles predefinidos mantenidos por la comunidad, puedes instalar además:

apt install apparmor-profiles-extra

Estos perfiles adicionales abarcan un buen número de servicios y aplicaciones, muchos de ellos expuestos a red y especialmente interesantes de confinar.

Gestión básica de perfiles: enforce, complain, disable y reload

Una vez tienes AppArmor funcionando, la clave está en gestionar bien los perfiles. Cada archivo dentro de /etc/apparmor.d/ define las reglas de un perfil, y su nombre suele corresponderse con la ruta del ejecutable sustituyendo las barras por puntos. Por ejemplo, /etc/apparmor.d/bin.ping es el perfil de /bin/ping.

Lo normal es que no tengas que editar estos ficheros a mano para cambiar el modo; para eso existen utilidades específicas. Por ejemplo, para forzar que un perfil concreto entre en modo estricto (enforce) puedes usar:

sudo aa-enforce /usr/sbin/cupsd

Si, al contrario, quieres poner un perfil en modo relajado (complain) porque sospechas que está dando problemas o quieres afinarlo sin bloquear tráfico, harías:

sudo aa-complain /usr/sbin/privoxy

Estos comandos aceptan tanto la ruta del ejecutable como la ruta al archivo de perfil. De hecho, si quieres cambiar el modo global de todos los perfiles definidos en /etc/apparmor.d/, podrías ejecutar:

sudo aa-complain /etc/apparmor.d/*

o en sentido contrario:

sudo aa-enforce /etc/apparmor.d/*

En situaciones más extremas, puede que quieras deshabilitar temporalmente un perfil concreto. Para ello existe aa-disable:

sudo aa-disable /etc/apparmor.d/usr.sbin.cupsd

Y si lo que necesitas es revisar con lupa todo lo que hace una aplicación, incluso lo que normalmente se permite, tienes el modo de auditoría con aa-audit, que hace que todas las llamadas controladas queden registradas sin bloquearlas.

Cuando modifiques manualmente un perfil o quieras recargarlo desde su fichero, puedes usar apparmor_parser para cargar o recargar perfiles concretos:

cat /etc/apparmor.d/profile.name | sudo apparmor_parser -a # cargar
cat /etc/apparmor.d/profile.name | sudo apparmor_parser -r # recargar

Y si lo que te interesa es recargar todos los perfiles activos en el sistema, puedes tirar del script de init (o su equivalente en systemd en distros modernas):

/etc/init.d/apparmor reload

Explorar y entender los perfiles existentes

Los perfiles cargados en el kernel son un reflejo de los ficheros que residen en /etc/apparmor.d/. Para listar el contenido del directorio puedes hacer:

sudo ls /etc/apparmor.d

Verás nombres como usr.sbin.sshd, usr.bin.man, etc. Muchos perfiles de la propia distribución se agrupan en subdirectorios como /etc/apparmor.d/local, pensados para variaciones locales sin tocar el perfil principal.

Si te pica la curiosidad y quieres ver las reglas de un perfil concreto, basta con:

sudo cat /etc/apparmor.d/usr.sbin.sshd

A primera vista, la sintaxis puede resultar algo árida, pero muchas líneas están comentadas con explicaciones sencillas que ayudan a entender el propósito de cada bloque. En cualquier caso, si no controlas bien la sintaxis, es mejor no editar estos archivos a mano y usar en su lugar las herramientas interactivas de generación y ajuste.

Detectar procesos sin perfil y priorizar qué confinar

No todos los programas de tu sistema tendrán un perfil de AppArmor asociado. Es más, la mayoría no lo tendrá. Los que interesa confinar primero suelen ser aquellos expuestos a la red, ya sea porque abren puertos o porque manejan datos potencialmente peligrosos.

AppArmor incluye la herramienta aa-unconfined para listar procesos que están escuchando en la red pero no tienen perfil:

aa-unconfined

Si añades el parámetro --paranoid, la utilidad mostrará todos los procesos en ejecución que mantienen al menos una conexión de red activa y no se encuentran confinados:

aa-unconfined --paranoid

Esta lista te sirve de guía para decidir por dónde empezar. Por ejemplo, podrías descubrir que un servicio web, un proxy o un demonio de base de datos están operando sin ninguna política AppArmor, lo que es una invitación a generarles un perfil dedicado.

Creación de nuevos perfiles con aa-genprof y aa-logprof

Crear un perfil desde cero puede intimidar, pero AppArmor ofrece herramientas de “modo aprendizaje” que simplifican mucho la tarea. La idea es sencilla: ejecutas el programa en modo complain, dejas que haga su trabajo, y luego construyes el perfil a partir de los logs generados por AppArmor.

  Consejos de seguridad para proteger criptomonedas: guía práctica contra fraudes y hackeos

La utilidad principal para esto es aa-genprof. Su sintaxis básica es:

sudo aa-genprof nombre_ejecutable

Por ejemplo, para generar un perfil para dhclient (cliente DHCP), podrías lanzar:

sudo aa-genprof dhclient

El proceso típico de trabajo es algo así: aa-genprof crea un perfil inicial vacío o muy abierto, lo carga en modo complain y te pide que, en otra terminal, uses la aplicación que quieres perfilar (en este caso, que lances o fuerces la obtención de una nueva IP con dhclient).

Mientras el programa funciona, AppArmor va registrando en los logs todas las acciones que, de estar en modo enforce, se hubieran bloqueado. Después, al volver a aa-genprof y elegir la opción de escanear los eventos, la herramienta te presenta una lista interactiva de violaciones detectadas junto con sugerencias de reglas.

Un ejemplo de primer evento puede ser una ejecución de script auxiliar:

Perfil: /usr/sbin/dhclient
Ejecutar: /usr/sbin/dhclient-script
Severity: desconocido
(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inalizar

A partir de aquí, decides qué hacer con los procesos hijos: lanzar el script con el mismo perfil (Inherit), con un subperfil (Child), con un perfil dedicado (Profile/Named), sin confinar (Unconfined) o impedir su ejecución (Deny).

AppArmor también gestiona capabilities, que son permisos especiales del kernel originalmente reservados a root (por ejemplo, usar sockets raw, cambiar la hora del sistema, etc.). Durante el profiling, verás cosas como:

Perfil: /usr/sbin/dhclient
Capability: net_raw
Severity: 8
(A)llow / (D)eny / (I)gnorar / Audi(t) / Abo(r)t / (F)inalizar

En cada caso decides si permitir, denegar, ignorar (no crear regla), auditar o abortar. Lo mismo se aplica a accesos a ficheros, donde se te mostrarán rutas concretas, modos de acceso (lectura, escritura, etc.) y posibles abstracciones reutilizables.

Las abstracciones son conjuntos de reglas comunes empaquetadas en ficheros reutilizables (por ejemplo, <abstractions/nameservice> para todo lo relacionado con resolución de nombres). En lugar de añadir una regla suelta para /etc/nsswitch.conf, puedes incluir la abstracción y simplificar el perfil.

Al final del proceso, aa-genprof te ofrece guardar los perfiles modificados y los recarga automáticamente en modo enforce, de forma que el programa queda confinado con las reglas que acabas de aprobar. Si más adelante detectas nuevos comportamientos, siempre puedes volver a ejecutar aa-genprof o, de forma más directa, aa-logprof sobre los logs registrados.

De hecho, aa-genprof no es más que un pequeño script que usa por debajo aa-logprof: crea un perfil vacío, lo pone en complain, lanza el programa y, a continuación, llama a aa-logprof para ir construyendo el perfil a partir de las violaciones registradas. Puedes usar aa-logprof por separado siempre que quieras refinar perfiles existentes a partir de nuevos eventos.

Detección de cambios en código y directorios con shell y hash

Además de las capacidades de control de acceso, en muchos casos interesa detectar si el código de un script o el contenido de un directorio ha cambiado entre ejecuciones, por ejemplo para disparar una copia de seguridad completa solo cuando haya modificaciones, en lugar de hacer incrementales continuas.

No hablamos aquí de monitorización en tiempo real (para eso tendrías inotify y herramientas derivadas), sino de una comprobación puntual: ejecutas un script que revisa el estado del directorio y, si detecta cambios respecto a la última vez, actúa.

Un enfoque sencillísimo para un directorio completo, sin excepciones, pasa por usar stat. El siguiente esqueleto ilustra la idea:

DIR_TO_CHECK='/dir/to/check'
OLD_STAT_FILE='/home/johndoe/old_stat.txt'

if ; then
OLD_STAT=$(cat «$OLD_STAT_FILE»)
else
OLD_STAT=»nothing»
fi

NEW_STAT=$(stat -t «$DIR_TO_CHECK»)

if ; then
echo ‘Directory has changed. Do something!’
# aquí haces copia de seguridad, validaciones, etc.
echo «$NEW_STAT» > «$OLD_STAT_FILE»
fi

La lógica es muy simple: almacenas el resultado de stat en un fichero, y en la próxima ejecución lo comparas con el nuevo resultado. Si difiere, asumes que ha cambiado algo (tamaño, tiempos, etc.) en el directorio. Esta técnica es rápida pero algo tosca, y no te deja excluir subrutas fácilmente.

Si quieres comprobar un directorio pero excluyendo ciertos ficheros o subdirectorios (por ejemplo un tmp/ local o archivos de log), puedes montar algo más elaborado combinando find, du, sort y sha1sum para obtener una “huella” del estado del árbol que te interesa.

Un ejemplo de script podría ser:

DIR_TO_CHECK='/dir/to/check'
PATH_TO_EXCLUDE="/dir/to/check/tmp*"
OLD_SUM_FILE='/home/johndoe/old_sum.txt'

if ; then
OLD_SUM=$(cat «$OLD_SUM_FILE»)
else
OLD_SUM=»nothing»
fi

NEW_SUM=$(find «$DIR_TO_CHECK»/* \! -path «$PATH_TO_EXCLUDE» -print0 \
| xargs -0 du -b –time –exclude=»$PATH_TO_EXCLUDE» \
| sort -k4,4 \
| sha1sum \
| awk ‘{print $1}’)

if ; then
echo «Directory has changed. Do something!»
echo «$NEW_SUM» > «$OLD_SUM_FILE»
fi

Aquí la clave está en la línea donde se calcula NEW_SUM:

  • find ... \! -path "$PATH_TO_EXCLUDE" -print0: se listan todos los ficheros bajo el directorio salvo aquellos que coinciden con el patrón a excluir. El -print0 hace que los nombres se separen con un carácter nulo para evitar líos con espacios y caracteres raros.
  • xargs -0 du -b --time --exclude=...: para cada fichero obtenido, se calcula el tamaño en bytes y la información de tiempo (según opciones), construyendo una lista en la que cada línea representa un objeto del sistema de ficheros y de la que se excluyen de nuevo las rutas no deseadas.
  • sort -k4,4: se ordena la lista según la columna que contenga la ruta (normalmente la cuarta), de modo que el orden sea determinista y cualquier cambio se refleje en la secuencia.
  • sha1sum | awk '{print $1}': se calcula la suma SHA1 de toda la lista, lo que genera una huella corta que “representa” el estado completo del directorio (sin los excluidos). Un solo cambio en tamaño, ruta o timestamp hará que la huella varíe.

Con esto, cada vez que ejecutes el script sabrás si, entre una run y la siguiente, se ha modificado, agregado, eliminado o renombrado algo relevante en el árbol. Y eso te permite enganchar otras acciones: regenerar copias de seguridad completas, lanzar validaciones de integridad, recargar servicios, etc.

  Cómo Desbloquear un Celular con la Huella de otra Persona: Una Guía Paso a Paso

Cómo encaja AppArmor en la detección de cambios en scripts

Las técnicas anteriores, por sí solas, ya te permiten detectar modificaciones en el código de un script o en sus recursos asociados. Pero si combinas esto con AppArmor, puedes ir un paso más allá y hacer que el propio sistema de seguridad te avise cuando un script empieza a hacer cosas para las que no estaba pensado.

Imagina que tienes un script que debería limitarse a leer un conjunto de ficheros y escribir en un directorio concreto. Si le defines un perfil de AppArmor que solo permite lectura en /opt/misdatos/ y escritura en /var/log/miscript/, cualquier intento de acceder a otros sitios generará eventos de violación en los logs (en modo complain) o se bloqueará de plano (en modo enforce).

De este modo, si alguien modifica el script (o lo sustituye por uno malicioso) para que borre archivos en /etc/ o envíe datos a través de la red, AppArmor actuará como red de seguridad. Además, revisando los logs con aa-logprof o directamente en /var/log/syslog/journalctl, podrás detectar comportamientos anómalos que delaten cambios en el código o en la lógica de ejecución.

Una estrategia práctica es combinar ambos enfoques:

  • Por un lado, usar un pequeño script de hash (basado en stat o en la suma de contenidos) para verificar si el código del script y sus recursos han cambiado desde la última revisión.
  • Por otro, colocar el script bajo un perfil AppArmor bien ajustado que limite su comportamiento y registre cualquier intento de salirse del guion.

Si ambos sistemas dan señales (hash distinto y violaciones nuevas en AppArmor), tienes una indicación bastante clara de que algo ha cambiado y conviene inspeccionar a fondo.

Problemas habituales relacionados con AppArmor y la provisión de VMs Linux

En entornos de nube como Azure, AppArmor suele convivir con otras piezas críticas del sistema, como cloud-init y el agente de Linux de Azure. Cuando se crean máquinas virtuales a partir de imágenes personalizadas, no es raro encontrarse con errores de aprovisionamiento que, aunque no se deban directamente a AppArmor, sí afectan a servicios que pueden estar confinados por perfiles.

Un caso típico: al desplegar una VM desde una imagen, el estado se queda en creating durante un buen rato y luego pasa a failed con mensajes como:

Provisioning failed. OS Provisioning for VM 'sentilo' did not finish in the allotted time...

O bien:

OSProvisioningInternalError: The VM encountered an error during deployment...

Para diagnosticar estos problemas, se recurre al registro de consola serie habilitando los diagnósticos de arranque de Azure, lo que permite ver desde las opciones de línea de comandos del kernel hasta la secuencia de objetivos de systemd, la ejecución de cloud-init y del agente de Azure, la configuración de red, la generación de claves SSH, etc.

En esos logs se comprueba, por ejemplo, si se ha alcanzado el objetivo «Network is Online», si cloud-init ha completado sus fases (init-local, init, módulos de config y final), si se han montado correctamente los discos ISO de aprovisionamiento (necesitan el driver UDF) o si el agente de Azure marca Finished provisioning.

Entre los errores frecuentes están:

  • Módulo UDF bloqueado o ausente: el disco de aprovisionamiento no se monta y cloud-init no puede leer los metadatos, apareciendo mensajes de “No Azure metadata found”.
  • Problemas de Unicode en etiquetas de VM o contraseñas, especialmente con versiones antiguas de cloud-init que no manejan bien caracteres no ASCII.
  • Montaje de /var/tmp con noexec, que impide a cloud-init ejecutar dhclient cuando éste se copia a esa ruta en versiones previas a la 20.3.

Todo esto se soluciona actualizando a versiones recientes de cloud-init, corrigiendo los parámetros de montaje y asegurando que los módulos necesarios del kernel (como UDF) no están bloqueados en /etc/modprobe.d/. Si además usas AppArmor en estas VMs, conviene revisar que no haya perfiles excesivamente restrictivos afectando a componentes como cloud-init, dhclient, systemd-networkd o el agente de Azure, ya que podrían interferir con el aprovisionamiento.

Desactivar completamente AppArmor (cuando no queda otra)

Aunque lo recomendable es ajustar perfiles y modos en lugar de tirar por la calle de en medio, en ocasiones muy concretas puede ser necesario desactivar AppArmor por completo, por ejemplo para descartar que esté causando un problema esotérico en un entorno de pruebas.

sudo /etc/init.d/apparmor stop
sudo update-rc.d -f apparmor remove

Y, si más adelante quieres volver a activarlo, simplemente lo inicias y lo registras de nuevo en los niveles de arranque por defecto:

sudo /etc/init.d/apparmor start
sudo update-rc.d apparmor defaults

Ten en cuenta que al desactivar AppArmor pierdes toda la capa de protección MAC que proporciona, con lo que los procesos quedan de nuevo limitados solo por los permisos DAC tradicionales. Lo más sensato es usar esta medida únicamente para diagnóstico puntual y, una vez identificado el problema, volver a habilitarlo y ajustar los perfiles conflictivos.

Con todo lo visto, se puede combinar sin demasiada complicación el uso de AppArmor para limitar el comportamiento de scripts y servicios con pequeñas técnicas de hashing y comparación para detectar cambios en el código y en los directorios clave de un sistema Linux, lo que aporta una capa extra de tranquilidad cuando se gestionan máquinas en producción o en la nube y no quieres que nada se mueva sin que te enteres.

programar tareas en linux con cron y at
Artículo relacionado:
Programar tareas en Linux con cron y at: guía práctica y completa