Seguridad básica
1. Introducción #
Docker facilita mucho la ejecución de aplicaciones.
Pero debemos recordar una idea importante:
1Un contenedor no es una barrera de seguridad absoluta.
Los contenedores comparten determinados recursos con el sistema anfitrión y dependen del motor Docker.
Por eso debemos evitar configuraciones que concedan más permisos de los necesarios.
En este bloque veremos:
1usuarios no root 2USER 3modo rootless 4montajes de solo lectura 5--read-only 6capabilities 7--cap-drop 8--privileged 9secretos 10permisos de volúmenes 11imágenes de confianza 12buenas prácticas de Dockerfile
2. Principio de mínimo privilegio #
Una regla básica de seguridad es:
1dar solamente los permisos necesarios
Si una aplicación únicamente necesita:
1leer archivos 2escuchar peticiones HTTP 3acceder a una base de datos
no debería disponer de permisos para:
1modificar todo el sistema 2administrar dispositivos 3cambiar configuraciones del host 4realizar operaciones privilegiadas
A esto se le conoce como:
1principio de mínimo privilegio
3. El usuario root #
En sistemas Linux:
1root
es el usuario con mayores privilegios.
Dentro de muchos contenedores podemos encontrar:
1whoami
y obtener:
1root
Por ejemplo:
1docker run --rm debian whoami
podría mostrar:
1root
Que un proceso funcione como root dentro de un contenedor no equivale exactamente a ser root en el host, pero sigue siendo recomendable evitar privilegios innecesarios.
4. Comprobar el usuario #
Podemos crear:
1docker run -it --rm debian bash
Dentro:
1whoami
También:
1id
Podremos comprobar con qué:
1UID 2GID 3usuario
estamos trabajando.
5. Crear un usuario en un Dockerfile #
Supongamos que tenemos una aplicación que no necesita privilegios elevados.
Podemos crear un usuario específico.
Ejemplo:
1FROM debian 2 3RUN useradd -m appuser 4 5USER appuser 6 7CMD ["whoami"]
Construimos:
1docker build -t usuario-prueba .
Ejecutamos:
1docker run --rm usuario-prueba
Obtendremos:
1appuser
6. USER #
La instrucción:
1USER
establece el usuario que se utilizará para las siguientes instrucciones aplicables y como usuario predeterminado del contenedor.
Ejemplo:
1USER appuser
Docker recomienda utilizar un usuario no privilegiado cuando el servicio no necesita ejecutarse como root.
7. Ejemplo con una aplicación #
Podemos tener:
1FROM debian 2 3RUN useradd -m aplicacion 4 5WORKDIR /home/aplicacion 6 7COPY programa.sh . 8 9RUN chmod +x programa.sh 10 11USER aplicacion 12 13CMD ["./programa.sh"]
De esta manera:
1programa.sh
no se ejecuta como root.
8. Comprobar el usuario con docker exec #
Si tenemos un contenedor funcionando:
1docker exec mi-contenedor whoami
También:
1docker exec mi-contenedor id
Esto nos permite comprobar con qué usuario se ejecutan los procesos que iniciamos dentro del contenedor.
9. Ejecutar un comando con otro usuario #
Docker permite indicar un usuario mediante:
1--user
Por ejemplo:
1docker run --rm --user 1000:1000 debian id
La estructura es:
1UID:GID
Por ejemplo:
11000:1000
10. Rootless Docker #
Docker también dispone de un modo denominado:
1Rootless mode
En este modo tanto el daemon como los contenedores pueden ejecutarse sin privilegios root tradicionales.
La finalidad es reducir el impacto potencial de vulnerabilidades en Docker o en el runtime.
Para este curso no necesitamos configurarlo, pero conviene conocer el concepto:
1Docker tradicional 2 ↓ 3daemon con privilegios elevados 4 5 6Docker Rootless 7 ↓ 8daemon y contenedores 9sin root tradicional
11. No montar más del host de lo necesario #
En el bloque de volúmenes vimos:
1-v
Por ejemplo:
1docker run \ 2 -v C:/web:/usr/share/nginx/html \ 3 nginx
Estamos dando al contenedor acceso a:
1C:/web
Por tanto debemos evitar montajes excesivamente amplios.
12. Ejemplo peligroso conceptualmente #
No tendría sentido dar acceso a todo el sistema de archivos del host si la aplicación solo necesita una carpeta concreta.
Por ejemplo, montar:
1/
del host dentro de un contenedor da acceso a una cantidad enorme de información.
Es mejor:
1montar solamente el directorio necesario
13. Montajes de solo lectura #
Cuando un contenedor únicamente necesita leer archivos podemos utilizar:
1:ro
Por ejemplo:
1docker run -d \ 2 -p 8080:80 \ 3 -v C:/web:/usr/share/nginx/html:ro \ 4 nginx
Aquí:
1ro
significa:
1read only
14. Ventaja de :ro #
Tenemos:
1HOST 2C:/web 3 │ 4 │ lectura 5 ↓ 6CONTENEDOR
El contenedor puede utilizar los archivos, pero reducimos la posibilidad de que los modifique accidentalmente.
Siempre que una aplicación solo necesite leer un volumen, resulta recomendable considerar:
1:ro
15. Sistema de archivos de solo lectura #
También podemos iniciar un contenedor con:
1--read-only
Por ejemplo:
1docker run --read-only nginx
Esto hace que el sistema de archivos raíz del contenedor sea de solo lectura, excepto otros puntos de almacenamiento que configuremos explícitamente.
16. ¿Por qué puede ser útil? #
Una aplicación comprometida podría intentar escribir archivos dentro del contenedor.
Con:
1--read-only
reducimos las ubicaciones donde puede escribir.
Por ejemplo:
1docker run \ 2 --read-only \ 3 nginx
Sin embargo, algunas aplicaciones necesitan escribir en directorios temporales o de datos.
En esos casos debemos proporcionar los puntos necesarios.
17. Datos que sí necesitan escritura #
Podemos tener:
1APLICACIÓN 2 │ 3 ├── código → solo lectura 4 │ 5 └── datos → escritura
Una buena estrategia es separar:
1aplicación
de:
1datos modificables
mediante volúmenes específicos.
18. No almacenar contraseñas en la imagen #
Imaginemos un Dockerfile:
1FROM debian 2 3ENV PASSWORD=MiClaveSuperSecreta
No es una buena idea para un secreto real.
Las imágenes pueden:
1compartirse 2publicarse 3inspeccionarse 4almacenarse en registros
Por tanto debemos evitar introducir credenciales sensibles directamente en ellas.
19. Tampoco copiar archivos de secretos #
Otro error sería:
1COPY contraseñas.txt /app/contraseñas.txt
Si después publicamos esa imagen:
1docker push
podríamos distribuir esas credenciales junto con la imagen.
20. Secretos durante la construcción #
Docker BuildKit permite proporcionar secretos temporalmente durante determinadas instrucciones de construcción.
Conceptualmente:
1SECRETO 2 │ 3 ↓ 4docker build 5 │ 6 ↓ 7disponible durante un paso 8 │ 9 ↓ 10no se incorpora directamente 11a la imagen final
Esto es preferible a escribir secretos directamente en un Dockerfile.
21. Ejemplo conceptual #
Un build secret puede montarse temporalmente dentro de una instrucción RUN.
Por ejemplo:
1RUN \ 2 comando-que-necesita-la-clave
El secreto no debe formar parte permanente de la capa resultante.
Es una función más avanzada, pero conviene conocerla.
22. Variables de entorno y secretos #
En prácticas hemos utilizado:
1-e MYSQL_ROOT_PASSWORD=Ad1234
Esto resulta cómodo para aprender.
Sin embargo, una contraseña real no debería tratarse igual que una variable cualquiera.
Debemos distinguir:
1CONFIGURACIÓN 2 3PUERTO=8080 4ENTORNO=produccion 5IDIOMA=es
de:
1SECRETOS 2 3contraseñas 4tokens 5claves API 6certificados privados
23. Docker Compose y secretos #
Docker Compose dispone de mecanismos para gestionar:
1secrets
en lugar de escribir determinadas credenciales directamente dentro del archivo.
Para un curso inicial basta con recordar:
1No incrustar secretos en una imagen. 2No publicar secretos en Git. 3No poner claves reales en ejemplos compartidos.
24. Imágenes de confianza #
Cuando ejecutamos:
1docker pull alguna-imagen
estamos descargando software que posteriormente ejecutaremos.
Por tanto debemos comprobar:
1quién publica la imagen 2qué documentación tiene 3si es oficial 4si está mantenida 5qué versión estamos descargando
25. Preferir imágenes oficiales #
Por ejemplo, para Nginx:
1docker pull nginx
Para MySQL:
1docker pull mysql
Para Debian:
1docker pull debian
Es preferible utilizar imágenes oficiales o mantenidas por fuentes de confianza frente a imágenes desconocidas sin necesidad.
26. Cuidado con latest #
Podemos utilizar:
1docker pull nginx
que normalmente trabaja con:
1latest
Pero en entornos donde queremos reproducibilidad puede ser conveniente fijar una versión concreta.
Ejemplo:
1FROM node:24
en lugar de depender siempre de:
1FROM node:latest
La versión concreta dependerá de nuestra aplicación.
27. Actualizar las imágenes #
Una imagen antigua puede contener:
1librerías antiguas 2software vulnerable 3paquetes sin actualizar
Por tanto debemos reconstruir y actualizar periódicamente nuestras imágenes cuando corresponda.
No debemos pensar:
1"Como está dentro de Docker, ya es seguro"
Docker no elimina las vulnerabilidades del software que contiene la imagen.
28. Reducir el tamaño de las imágenes #
Una imagen que contiene herramientas innecesarias puede aumentar:
1tamaño 2superficie de ataque 3tiempo de descarga 4tiempo de construcción
Es recomendable incluir únicamente lo necesario para ejecutar la aplicación.
29. No instalar herramientas innecesarias #
Por ejemplo, en un servidor de producción quizá no necesitemos:
1nano 2vim 3curl 4gcc 5git 6compiladores 7herramientas de depuración
si la aplicación no las utiliza.
Durante clase podemos instalarlas para practicar, pero en una imagen final debemos valorar si realmente son necesarias.
30. Multi-stage builds #
Docker permite construir imágenes utilizando varias etapas.
Por ejemplo:
1ETAPA 1 2 ↓ 3compilar aplicación 4 5 6ETAPA 2 7 ↓ 8copiar únicamente 9el resultado necesario
Esto ayuda a reducir el contenido de la imagen final.
31. Ejemplo conceptual #
Podemos tener:
1FROM node:24 AS build 2 3WORKDIR /app 4COPY . . 5RUN npm install 6RUN npm run build 7 8 9FROM nginx 10 11COPY /app/dist /usr/share/nginx/html
La imagen final contiene:
1Nginx 2+ 3archivos compilados
pero no necesita contener todas las herramientas utilizadas durante la compilación.
32. .dockerignore #
Ya vimos:
1.dockerignore
Este archivo también tiene importancia desde el punto de vista de seguridad.
Podemos evitar enviar al contexto de construcción archivos como:
1.env 2.git 3node_modules 4contraseñas.txt 5claves 6certificados privados
Por ejemplo:
1.env 2.git 3*.pem 4*.key 5secrets/
33. Importante #
.dockerignore ayuda a evitar que ciertos archivos se envíen durante la construcción.
Pero no sustituye a una gestión correcta de secretos.
Si un secreto no debería estar en el proyecto, lo mejor es:
1no almacenarlo allí
34. Capacidades Linux #
Docker utiliza las:
1Linux capabilities
para dividir ciertos privilegios tradicionales de root en capacidades más pequeñas.
Por ejemplo:
1modificar determinadas configuraciones 2administrar red 3cambiar propietarios 4enviar determinadas señales
Docker ya elimina varias capacidades por defecto.
Además podemos eliminar otras.
35. --cap-drop #
Podemos retirar capacidades mediante:
1--cap-drop
Por ejemplo:
1docker run --cap-drop ALL imagen
Esto elimina todas las capacidades adicionales disponibles para el contenedor.
Después podemos añadir únicamente las imprescindibles si fueran necesarias.
36. Ejemplo conceptual #
Tenemos:
1CONTENEDOR 2 │ 3 ├── capacidad A 4 ├── capacidad B 5 ├── capacidad C 6 └── capacidad D
Podemos reducir:
1CONTENEDOR 2 │ 3 └── solamente capacidades necesarias
Esto sigue el principio:
1mínimo privilegio
37. --cap-add #
También existe:
1--cap-add
que permite añadir una capacidad específica.
Por ejemplo:
1docker run \ 2 --cap-drop ALL \ 3 --cap-add <CAPACIDAD_NECESARIA> \ 4 imagen
Para un curso inicial no necesitamos memorizar todas las capabilities.
Lo importante es conocer la idea.
38. Evitar --privileged #
Existe una opción:
1--privileged
Por ejemplo:
1docker run --privileged imagen
Concede al contenedor permisos muy elevados.
No debemos utilizar:
1--privileged
como solución rápida cuando algo no funciona.
39. Regla práctica #
Si una guía dice:
1"añade --privileged"
debemos preguntarnos:
1¿Por qué lo necesita? 2¿Qué permiso concreto falta? 3¿Existe una alternativa más limitada?
La idea es:
1NO: 2dar todos los permisos 3 4 5SÍ: 6dar solamente el permiso necesario
40. Socket de Docker #
En algunos ejemplos avanzados podemos encontrar:
1/var/run/docker.sock
Este socket permite comunicarse con el daemon Docker.
Dar acceso a un contenedor al socket Docker supone conceder un nivel de control muy elevado sobre Docker.
Por tanto no debemos montarlo dentro de un contenedor salvo que entendamos claramente las implicaciones.
41. Usuario docker en Linux #
En instalaciones Linux puede existir un grupo:
1docker
Los usuarios con acceso al daemon Docker tienen un nivel de control muy elevado sobre el sistema.
Por tanto:
1no debemos dar acceso a Docker a usuarios no confiables
El daemon puede crear contenedores, montar directorios del host y realizar operaciones muy potentes.
42. Puertos #
También debemos publicar únicamente los puertos necesarios.
Por ejemplo, si tenemos:
1web 2mysql
y solamente Nginx necesita ser accesible desde nuestro ordenador:
1services: 2 3 web: 4 image: nginx 5 ports: 6 - "8080:80" 7 8 mysql: 9 image: mysql
No necesitamos necesariamente:
1ports: 2 - "3306:3306"
para MySQL.
43. Menos puertos expuestos #
Podemos verlo así:
1HOST 2 │ 3 │ 8080 4 ↓ 5NGINX 6 │ 7 │ red interna Docker 8 ↓ 9MYSQL
MySQL puede comunicarse internamente con la aplicación sin estar publicado hacia el host.
Esto reduce servicios innecesariamente accesibles.
44. Separación mediante redes #
También podemos utilizar redes para separar servicios.
Por ejemplo:
1frontend 2 │ 3 ↓ 4 web 5 6 7backend 8 │ 9 ├── app 10 └── mysql
No todos los contenedores tienen por qué estar conectados a todas las redes.
45. Volúmenes y permisos #
Cuando montamos:
1-v C:/datos:/datos
debemos recordar que el contenedor puede tener acceso a esos archivos.
Si solo necesita leer:
1-v C:/datos:/datos:ro
es preferible.
No debemos montar directorios sensibles sin necesidad.
46. No guardar datos sensibles en capas de imagen #
Una imagen Docker puede conservar información de capas anteriores.
Por tanto no debemos hacer algo como:
1COPY contraseña.txt /tmp/contraseña.txt 2RUN utilizar-contraseña 3RUN rm /tmp/contraseña.txt
y asumir automáticamente que el secreto nunca formó parte de la construcción.
Para secretos de build debemos utilizar mecanismos específicos de BuildKit.
47. Separar configuración e imagen #
Una buena imagen debería poder utilizarse en distintos entornos:
1desarrollo 2pruebas 3producción
sin necesidad de reconstruirla simplemente para cambiar:
1puerto 2URL 3nombre de base de datos 4configuración
Estas opciones pueden introducirse externamente mediante configuración.
48. No ejecutar todo como root #
Una imagen sencilla podría ser:
1FROM python:3 2 3WORKDIR /app 4 5COPY app.py . 6 7CMD ["python", "app.py"]
Podemos mejorarla creando un usuario:
1FROM python:3 2 3RUN useradd -m appuser 4 5WORKDIR /app 6 7COPY app.py . 8 9RUN chown -R appuser:appuser /app 10 11USER appuser 12 13CMD ["python", "app.py"]
Ahora la aplicación se ejecutará como:
1appuser
49. COPY --chown #
Docker permite asignar propietarios durante determinados COPY.
Por ejemplo:
1COPY . /app
Esto puede evitar tener que realizar un:
1chown
posteriormente.
50. Ejemplo mejorado #
1FROM python:3 2 3RUN useradd -m appuser 4 5WORKDIR /app 6 7COPY app.py . 8 9USER appuser 10 11CMD ["python", "app.py"]
Tenemos una imagen sencilla que:
1crea usuario 2copia aplicación 3asigna permisos 4abandona root 5ejecuta aplicación
51. Práctica: comprobar root #
Ejecuta:
1docker run --rm debian whoami
Después:
1docker run --rm debian id
Anota:
1usuario 2UID 3GID
52. Práctica: crear un usuario #
Crea un Dockerfile:
1FROM debian 2 3RUN useradd -m alumno 4 5USER alumno 6 7CMD ["id"]
Construye:
1docker build -t debian-alumno .
Ejecuta:
1docker run --rm debian-alumno
Comprueba que el proceso no se ejecuta como:
1root
53. Práctica: montaje de solo lectura #
Crea una carpeta:
1C:/docker-seguridad
Dentro:
1datos.txt
Ejecuta:
1docker run -it \ 2 --rm \ 3 -v C:/docker-seguridad:/datos:ro \ 4 debian bash
Dentro:
1cat /datos/datos.txt
Debería poder leerlo.
54. Intentar modificar #
Dentro:
1echo "nuevo" > /datos/nuevo.txt
La operación debería fallar porque el montaje es:
1read only
Salimos:
1exit
55. Práctica con Nginx #
Tenemos:
1C:/web/index.html
Ejecutamos:
1docker run -d \ 2 --name web-segura \ 3 -p 8080:80 \ 4 -v C:/web:/usr/share/nginx/html:ro \ 5 nginx
Podemos acceder:
1http://localhost:8080
Nginx puede leer la página, pero el montaje está configurado como solo lectura.
56. Práctica con --read-only #
Ejecuta:
1docker run --rm --read-only debian touch /prueba.txt
La operación debería fallar porque intentamos escribir en el sistema de archivos raíz del contenedor.
Compara con:
1docker run --rm debian touch /prueba.txt
57. Ejercicio práctico #
Crea una imagen con estas características:
1Imagen base: 2debian 3 4Usuario: 5appuser 6 7Directorio: 8/app 9 10Fichero: 11datos.txt
El Dockerfile debe:
- Crear
appuser. - Crear
/app. - Copiar
datos.txt. - Asignar correctamente el archivo al usuario.
- Utilizar
USER appuser. - Mostrar el contenido del fichero al arrancar.
58. Ejercicio con Nginx #
Crea un servidor:
1nombre: 2nginx-seguro 3 4puerto: 58085 → 80 6 7directorio host: 8C:/web-segura 9 10directorio contenedor: 11/usr/share/nginx/html
Requisitos:
1montaje de solo lectura 2sin --privileged 3solamente puerto 8085 publicado
Después:
- Comprueba la página.
- Consulta
docker inspect. - Comprueba el montaje.
- Entra mediante
docker exec. - Intenta crear un archivo dentro del directorio montado.
- Comprueba que no puede modificarlo.
59. Ejercicio de análisis #
Indica cuál de estas opciones es preferible.
Caso A #
1docker run \ 2 --privileged \ 3 -v C:/:/host \ 4 mi-aplicacion
Caso B #
1docker run \ 2 -v C:/app/datos:/datos:ro \ 3 mi-aplicacion
Si la aplicación solamente necesita leer:
1C:/app/datos
la segunda configuración proporciona muchos menos privilegios.
60. Checklist de seguridad básica #
Antes de ejecutar un contenedor podemos preguntarnos:
1¿Necesita ejecutarse como root? 2 3¿Necesita todos esos puertos? 4 5¿Necesita escritura en ese volumen? 6 7¿Necesita acceder a todo ese directorio? 8 9¿Necesita --privileged? 10 11¿Necesita todas las capabilities? 12 13¿La imagen procede de una fuente fiable? 14 15¿Estoy utilizando una versión adecuada? 16 17¿He incluido alguna contraseña en la imagen? 18 19¿Hay archivos sensibles dentro del contexto de build?
61. Buenas prácticas de Dockerfile #
Una primera lista para el alumnado:
11. Utilizar imágenes de confianza. 2 32. Utilizar versiones controladas cuando interese reproducibilidad. 4 53. Crear imágenes pequeñas. 6 74. No instalar software innecesario. 8 95. Utilizar USER cuando sea posible. 10 116. Utilizar COPY para copias normales. 12 137. Utilizar .dockerignore. 14 158. No copiar secretos a la imagen. 16 179. Mantener actualizadas las imágenes. 18 1910. Utilizar multi-stage builds cuando ayuden a reducir la imagen.
Docker recomienda expresamente usar USER cuando un servicio pueda funcionar sin privilegios y utilizar COPY para copias normales, reservando ADD para los comportamientos adicionales que realmente se necesiten.
62. Buenas prácticas al ejecutar #
11. Publicar solamente los puertos necesarios. 2 32. Montar únicamente los directorios necesarios. 4 53. Usar :ro cuando solo necesitemos lectura. 6 74. Evitar --privileged. 8 95. Reducir capabilities cuando sea posible. 10 116. Limitar CPU y memoria. 12 137. Utilizar redes para separar servicios. 14 158. No almacenar credenciales dentro de la imagen. 16 179. Revisar logs y actualizaciones. 18 1910. No dar acceso al daemon Docker a usuarios no confiables.
63. Preguntas de repaso #
-
¿Qué significa el principio de mínimo privilegio?
-
¿Por qué es preferible evitar
rootcuando una aplicación no lo necesita? -
¿Para qué sirve
USER? -
¿Para qué sirve
--user? -
¿Qué es Docker Rootless?
-
¿Qué significa
:roen un volumen? -
¿Para qué sirve
--read-only? -
¿Por qué no debemos guardar contraseñas dentro de una imagen?
-
¿Qué es un build secret?
-
¿Por qué conviene utilizar imágenes de confianza?
-
¿Qué riesgo tiene utilizar imágenes antiguas?
-
¿Para qué sirve
.dockerignore? -
¿Qué son las Linux capabilities?
-
¿Para qué sirve
--cap-drop? -
¿Por qué debemos evitar
--privilegedsi no es necesario? -
¿Por qué debemos tener cuidado con
/var/run/docker.sock? -
¿Es obligatorio publicar el puerto de MySQL si solo lo utiliza otro contenedor?
-
¿Por qué puede ser interesante usar un multi-stage build?
-
¿Qué ventaja aporta
COPY --chown? -
¿Por qué montar solamente el directorio necesario mejora la seguridad?
64. Resumen de comandos #
Ejecutar con un usuario concreto #
1docker run --user 1000:1000 imagen
Volumen de solo lectura #
1docker run \ 2 -v C:/datos:/datos:ro \ 3 imagen
Sistema de archivos de solo lectura #
1docker run --read-only imagen
Eliminar capabilities #
1docker run --cap-drop ALL imagen
Añadir una capability concreta #
1docker run \ 2 --cap-drop ALL \ 3 --cap-add <CAPACIDAD> \ 4 imagen
65. Resumen de Dockerfile #
Usuario #
1USER appuser
Copiar con propietario #
1COPY . /app
Ejemplo #
1FROM python:3 2 3RUN useradd -m appuser 4 5WORKDIR /app 6 7COPY app.py . 8 9USER appuser 10 11CMD ["python", "app.py"]
66. Esquema final #
1CONTENEDOR 2 │ 3 ├── usuario no root 4 │ 5 ├── recursos limitados 6 │ 7 ├── capacidades mínimas 8 │ 9 ├── sistema de archivos protegido 10 │ 11 ├── puertos necesarios 12 │ 13 └── volúmenes necesarios
La idea fundamental es:
1NO 2↓ 3dar permisos y acceso 4"por si acaso" 5 6 7SÍ 8↓ 9dar únicamente aquello 10que la aplicación necesita
Docker ya reduce capacidades respecto a un sistema Linux completamente privilegiado, pero su propia documentación recomienda eliminar capacidades adicionales cuando no sean necesarias y controlar cuidadosamente quién tiene acceso al daemon Docker.
La seguridad en Docker no consiste en un único comando.
Es la suma de:
1imagen de confianza 2+ 3pocos privilegios 4+ 5usuario adecuado 6+ 7redes controladas 8+ 9volúmenes controlados 10+ 11secretos bien gestionados 12+ 13software actualizado