Docker

Docker es una plataforma de código abierto que permite la creación, despliegue y administración de aplicaciones dentro de contenedores. Los contenedores son entornos ligeros y aislados que agrupan una aplicación junto con todas sus dependencias, lo que facilita la portabilidad y la eficiencia del software. Docker se ha convertido en una de las tecnologías más populares debido a su capacidad para simplificar los procesos de desarrollo y despliegue de software en diferentes entornos.

Docker es altamente versátil y eficiente gracias a su enfoque en la contenedorización en lugar de la virtualización tradicional. En lugar de virtualizar un sistema operativo completo, Docker permite ejecutar múltiples contenedores sobre un solo núcleo del sistema operativo, compartiendo recursos como el kernel.

  • Aislamiento: Los contenedores funcionan en entornos aislados, lo que asegura que las aplicaciones no interfieran entre sí, incluso si se ejecutan en el mismo servidor.
  • Portabilidad: Los contenedores Docker pueden ejecutarse en cualquier lugar, ya sea en el equipo local de un desarrollador, en servidores en la nube o en centros de datos on-premise, garantizando que funcionarán de manera consistente en diferentes entornos.
  • Ligereza: A diferencia de las máquinas virtuales, los contenedores no necesitan un sistema operativo completo, lo que reduce el uso de recursos como CPU y memoria. Los contenedores son ligeros y se inician rápidamente.
  • Escalabilidad: Docker facilita la creación de microservicios, lo que permite a las organizaciones escalar sus aplicaciones de manera modular. Cada microservicio se ejecuta en su propio contenedor y puede ser gestionado de forma independiente.

Componentes

Docker se compone de varios elementos clave que trabajan en conjunto para proporcionar un ecosistema eficiente para el desarrollo y la ejecución de aplicaciones en contenedores:

  • Docker Engine: Es el corazón de Docker. Se trata de un motor cliente-servidor que gestiona los contenedores. Consta de tres componentes:
    1. Docker Daemon (dockerd): Es el servidor que se ejecuta en segundo plano y gestiona los contenedores.
    2. API REST: Permite a las aplicaciones comunicarse con el Docker Daemon para realizar tareas como crear, eliminar y gestionar contenedores.
    3. CLI (Interfaz de Línea de Comandos): La herramienta con la que los usuarios interactúan con Docker desde la terminal para ejecutar comandos.
  • Imágenes Docker: Son plantillas inmutables que contienen el código de una aplicación y todas las dependencias necesarias para ejecutarla. Las imágenes se almacenan en registros, como Docker Hub o registros privados.
  • Contenedores Docker: Son instancias ejecutables de imágenes de Docker. Cada contenedor se ejecuta de manera aislada en su propio entorno y utiliza recursos del sistema operativo anfitrión, lo que lo hace mucho más ligero que las máquinas virtuales.
  • Dockerfile: Es un archivo de texto que contiene un conjunto de instrucciones para construir una imagen Docker. Define cómo debe ser creada la imagen, desde qué base parte, qué dependencias necesita y qué comandos se deben ejecutar.
  • Docker Compose: Es una herramienta que permite definir y ejecutar aplicaciones multicontenedor. Mediante un archivo YAML, Docker Compose define cómo interactúan varios servicios dentro de una aplicación.
  • Registros Docker (Docker Registry): Son repositorios donde se almacenan las imágenes. Docker Hub es el registro más utilizado, pero también se pueden configurar registros privados.

Comandos de Administración

Docker ofrece una amplia gama de comandos para gestionar contenedores y redes. A continuación, se describen algunos de los más útiles para tareas comunes de administración:

Listar contenedores
Para listar todos los contenedores en ejecución, usamos el siguiente comando:
Si queremos ver también los contenedores detenidos:
Crear e iniciar contenedores
Para crear un nuevo contenedor e iniciarlo, utilizamos el comando docker run. Este comando descarga la imagen si no está presente localmente y luego crea el contenedor.

En este ejemplo, -d indica que el contenedor debe ejecutarse en segundo plano y nginx es la imagen que se utiliza.

También es posible ejecutar un contenedor interactivo con una terminal:
Inicia un contenedor de MySQL con una contraseña para el usuario root:
PostgreSQL:
Montar todo el sistema de archivos en un contenedor:

Este comando monta todo el sistema de archivos en el contenedor, permitiendo acceso completo a todo el sistema de archivos del host.

Detener y eliminar contenedores
Para detener un contenedor en ejecución:
Si queremos eliminar un contenedor (incluso si está detenido):
Eliminar todos los contenedores detenidos:
Eliminar todas las imágenes no usadas:
Cambiar la IP de un contenedor
Si es necesario asignar una IP personalizada a un contenedor, primero debemos crear una red personalizada:
Luego, iniciamos un contenedor en esta red con una IP específica:
Conectar contenedores entre sí
Para que dos contenedores puedan comunicarse entre ellos, es necesario conectarlos a la misma red:
En el segundo contenedor:

Después de esto, ambos contenedores podrán interactuar a través de la red interna.

Listar, crear y eliminar redes
Para listar las redes disponibles en Docker:
Para eliminar una red:
Administración de volúmenes
Crear un volumen:

Este comando crea un nuevo volumen que puede ser montado en los contenedores para persistir datos.

Listar volúmenes:
Inspeccionar un volumen:
Eliminar un volumen:
Montar un volumen al ejecutar un contenedor:

Ejemplo

Para descargar la GUI de Docker en Windows o Mac, se debe ingresar a la web oficial de Docker y seguir las instrucciones específicas para cada plataforma.

Para instalar Docker CLI en Linux, sigue estos pasos básicos:

Actualizar el sistema para evitar conflictos con las dependencias de Docker:
Instalar Docker CLI:
Verifica la instalación para asegurarte de que Docker está instalado correctamente, puedes verificar la versión instalada con el siguiente comando:

Docker Hub es un servicio basado en la nube que funciona como un repositorio central para imágenes Docker. Es una plataforma donde los desarrolladores pueden compartir, almacenar, y distribuir imágenes de contenedores que se pueden usar fácilmente en cualquier entorno que soporte Docker. Piensa en Docker Hub como un "centro de distribución" para aplicaciones y herramientas empaquetadas en contenedores Docker.

Puedes instalar Jenkins directamente desde Docker Hub usando un contenedor Docker. Jenkins tiene una imagen oficial en Docker Hub que puedes utilizar para configurar tu entorno de Jenkins de forma rápida y sencilla.

Para que Podman pueda buscar imágenes en Docker Hub, debes asegurarte de que Docker Hub esté configurado como un registro en tu sistema.

❏ Abre el archivo de configuración /etc/containers/registries.conf con tu editor de texto favorito, por ejemplo: sudo nano /etc/containers/registries.conf

❏ Edita el archivo, y asegúrate de tener algo como esto bajo la sección [registries.search]:

[registries.search] registries = ['docker.io']

❏ Verifica la instalación de Podman.

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman --help
Manage pods, containers and images Usage: podman [options] [command] Available Commands: attach Attach to a running container auto-update Auto update containers according to their auto-update policy build Build an image using instructions from Containerfiles commit Create new image based on the changed container compose Run compose workloads via an external provider such as docker-compose or podman-compose container Manage containers cp Copy files/folders between a container and the local filesystem create Create but do not start a container diff Display the changes to the object's file system events Show podman system events exec Run a process in a running container . . . [ snip ] . . .

❏ Después de haber actualizado el archivo de configuración, puedes intentar nuevamente tirar la imagen de Jenkins:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman pull jenkins/jenkins
Trying to pull docker.io/jenkins/jenkins:latest... Getting image source signatures Copying blob efcf9cb62df3 done | Copying blob d60eb3dc3297 done | Copying blob d64d58c3115c done | Copying blob 7d98d813d54f done | Copying blob 08b5bb3da083 done | Copying blob bfb71029c05d done | Copying blob 88ba2818e1c6 done | Copying blob db0580cf8138 done | Copying blob ac81c696d7e6 done | Copying blob 7396957ffcde done | Copying blob 7574cb8d8610 done | Copying blob 41a6c7718ec2 done | Copying config eae08093ff done | Writing manifest to image destination 32808093ffc9282c19f3955d10b94e78c806a0c670d7dfcfa00093f0dc4f3109

❏ Para listar las imágenes disponibles en tu sistema después de descargar una imagen puedes usar el siguiente comando:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman images
REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/jenkins/jenkins latest 32808093ffc9 31 hours ago 482 MB

❏ Si quieres más información sobre una imagen en particular (como los detalles de sus capas y configuraciones), puedes usar este comando para ver detalles de una imagen específica:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman inspect docker.io/jenkins/jenkins
[ { "Id": "32808093ffc9282c19f3955d10b94e78c806a0c670d7dfcfa00093f0dc4f3109", "Digest": "sha256:61ab9ddcd44e526858efecf7ccdf3e26352b08c4d19a3fce0318f0bd5edda2dd", "RepoTags": [ "docker.io/jenkins/jenkins:latest" ], "RepoDigests": [ "docker.io/jenkins/jenkins@sha256:61ab9ddcd44e526858efecf7ccdf3e26352b08c4d19a3fce0318f0bd5edda2dd", "docker.io/jenkins/jenkins@sha256:6e28580fa377c1526389a6cc5a41cca7e177f580b4d8541057f7ed28eaefa385" ], "Parent": "", "Comment": "", "Created": "2024-10-22T15:35:02.034543932Z", "Config": { "User": "jenkins", "ExposedPorts": { "50000/tcp": {}, "8080/tcp": {} }, "Env": [ "PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "LANG=C.UTF-8", "JENKINS_HOME=/var/jenkins_home", "JENKINS_SLAVE_AGENT_PORT=50000", "REF=/usr/share/jenkins/ref", "JENKINS_VERSION=2.482", "JENKINS_UC=https://updates.jenkins.io", "JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental", "JENKINS_INCREMENTALS_REPO_MIRROR=https://repo.jenkins-ci.org/incrementals", "COPY_REFERENCE_FILE_LOG=/var/jenkins_home/copy_reference_file.log", "JAVA_HOME=/opt/java/openjdk" ], "Entrypoint": [ "/usr/bin/tini", "--", "/usr/local/bin/jenkins.sh" ], "Volumes": { "/var/jenkins_home": {} }, "Labels": { "org.opencontainers.image.description": "The Jenkins Continuous Integration and Delivery server", . . . [ snip ] . . .

Antes de intentar ejecutar la imagen, puedes hacer una prueba para ver si está lista:

❏ Este comando ejecutará un contenedor temporal basado en la imagen de Jenkins y te dará acceso a una terminal en el contenedor. Si esto funciona correctamente, significa que la imagen se ha descargado y está lista para ser utilizada.

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman run -it docker.io/jenkins/jenkins /bin/bash
jenkins@2f23f8238fb9:/$ whoami jenkins jenkins@2f23f8238fb9:/$

❏ Para ejecutar Jenkins en un contenedor:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman run -d -p 8080:8080 -p 50000:50000 --name jenkins docker.io/jenkins/jenkins
d92e4cf14ec1b8ce059381e0be0ee6fe6558a39f488d9aaa7fc864bbbb2df389

❏ Antes de intentar acceder a Jenkins, asegúrate de que el contenedor esté en ejecución:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d92e4cf14ec1 docker.io/jenkins/jenkins:latest About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp, 8080/tcp, 50000/tcp jenkins

Ahora que el contenedor está corriendo, Jenkins está disponible en el puerto 8080 de tu máquina host. Abre un navegador web y ve a la siguiente URL: http://localhost:8080

❏ Cuando accedas a Jenkins por primera vez, verás una pantalla de "Unlock Jenkins". Para desbloquearlo, necesitarás el password de administrador generado durante la instalación. Para obtener esta contraseña, ejecuta el siguiente comando para ver los logs del contenedor de Jenkins:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman logs jenkins
. . . [ snip ] . . . 2024-10-24 03:31:41.979+0000 [id=35] INFO jenkins.InitReactorRunner$1#onAttained: Configuration for all jobs updated 2024-10-24 03:31:42.041+0000 [id=51] INFO hudson.util.Retrier#start: Attempt #1 to do the action check updates server 2024-10-24 03:31:42.603+0000 [id=35] INFO jenkins.install.SetupWizard#init: ************************************************************* ************************************************************* ************************************************************* Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: a3c09a2cba93412eb7815224e45409aa This may also be found at: /var/jenkins_home/secrets/initialAdminPassword ************************************************************* ************************************************************* ************************************************************* 2024-10-24 03:31:48.341+0000 [id=32] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization 2024-10-24 03:31:48.438+0000 [id=24] INFO hudson.lifecycle.Lifecycle#onReady: Jenkins is fully up and running . . . [ snip ] . . .

❏ Detener el contenedor:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman stop jenkins
jenkins

❏ Sí, una vez que el contenedor ha sido detenido pero no eliminado, puedes volver a iniciarlo usando el comando start. Si solo lo detuviste con podman stop, puedes reiniciarlo de la siguiente manera:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~podman start jenkins
jenkins
Para eliminar el contenedor:
Instala Docker Desktop.

Docker Compose

Docker Compose es una herramienta esencial en el ecosistema de Docker, diseñada para simplificar la definición, configuración y ejecución de aplicaciones compuestas por múltiples contenedores. Si Docker es la herramienta que permite crear y gestionar contenedores individuales, Docker Compose es la que permite orquestar varios contenedores que trabajan juntos para formar una aplicación completa.

Docker Compose es una herramienta que permite definir y gestionar aplicaciones multi-contenedor mediante un archivo de configuración en formato YAML (generalmente llamado docker-compose.yml). Este archivo describe los servicios, redes y volúmenes necesarios para que la aplicación funcione correctamente.

Con Docker Compose, puedes:

  • Definir todos los componentes de tu aplicación (bases de datos, servidores web, APIs, etc.) en un solo archivo.
  • Levantar y detener todos los servicios con un solo comando.
  • Gestionar las dependencias entre contenedores.
  • Simplificar el desarrollo, pruebas y despliegue de aplicaciones complejas.

Docker Compose es una herramienta poderosa para definir y ejecutar aplicaciones multi-contenedor. Sus componentes clave trabajan en conjunto para simplificar la gestión de aplicaciones complejas. Aquí están los componentes esenciales:

  1. Servicios: Cada servicio representa un contenedor en la aplicación. Por ejemplo, un servicio puede ser una base de datos, un servidor web o un microservicio.
  2. Redes: Docker Compose permite definir redes personalizadas para que los contenedores se comuniquen entre sí de manera aislada.
  3. Volúmenes: Los volúmenes permiten persistir datos fuera de los contenedores, lo que es útil para bases de datos o archivos de configuración.
  4. Variables de entorno: Puedes definir variables de entorno para configurar los servicios sin modificar el archivo docker-compose.yml.
Ejemplo con Docker Compose
Instala Docker Compose.
Descargar el repositorio de la herramienta:
Navegar al directorio del archivo de configuración docker-compose.yml:

❏ Levanta los servicios con Podman Compose:

ryuzak1@ubuntu: ~

ryuzak1@ubuntu:~BLOODHOUND_PORT=8888 podman-compose up
. . . [ snip ] . . . Creating docker-compose_app-db_1 ... done Creating docker-compose_graph-db_1 ... done Creating docker-compose_bloodhound_1 ... done Attaching to docker-compose_app-db_1, docker-compose_graph-db_1, docker-compose_bloodhound_1 app-db_1 | The files belonging to this database system will be owned by user "postgres". app-db_1 | This user must also own the server process. app-db_1 | app-db_1 | The database cluster will be initialized with locale "en_US.utf8". app-db_1 | The default database encoding has accordingly been set to "UTF8". app-db_1 | The default text search configuration will be set to "english". app-db_1 | app-db_1 | Data page checksums are disabled. app-db_1 | app-db_1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok app-db_1 | creating subdirectories ... ok app-db_1 | selecting dynamic shared memory implementation ... posix app-db_1 | selecting default max_connections ... 100 app-db_1 | selecting default shared_buffers ... 128MB app-db_1 | selecting default time zone ... Etc/UTC app-db_1 | creating configuration files ... ok graph-db_1 | Changed password for user 'neo4j'. IMPORTANT: this change will only take effect if performed before the database is started for the first time. graph-db_1 | 2025-03-13 17:47:41.149+0000 INFO Starting... graph-db_1 | 2025-03-13 17:47:41.401+0000 INFO This instance is ServerId{35da0670} (35da0670-1b37-4205-89e9-6f02ff387a22) graph-db_1 | 2025-03-13 17:47:42.017+0000 INFO ======== Neo4j 4.4.41 ======== graph-db_1 | 2025-03-13 17:47:43.309+0000 INFO Initializing system graph model for component 'security-users' with version -1 and status UNINITIALIZED graph-db_1 | 2025-03-13 17:47:43.318+0000 INFO Setting up initial user from `auth.ini` file: neo4j graph-db_1 | 2025-03-13 17:47:43.318+0000 INFO Creating new user 'neo4j' (passwordChangeRequired=false, suspended=false) graph-db_1 | 2025-03-13 17:47:43.330+0000 INFO Setting version for 'security-users' to 3 graph-db_1 | 2025-03-13 17:47:43.331+0000 INFO After initialization of system graph model component 'security-users' have version 3 and status CURRENT graph-db_1 | 2025-03-13 17:47:43.334+0000 INFO Performing postInitialization step for component 'security-users' with version 3 and status CURRENT graph-db_1 | 2025-03-13 17:47:43.487+0000 INFO Bolt enabled on [0:0:0:0:0:0:0:0]:7687. graph-db_1 | 2025-03-13 17:47:43.881+0000 INFO Remote interface available at http://localhost:7474/ graph-db_1 | 2025-03-13 17:47:43.884+0000 INFO id: C19ED0DBA9C27A6CEE2A321CBEF88CABA166F73C0A78470D3C3B52DCA7035820 app-db_1 | running bootstrap script ... ok app-db_1 | performing post-bootstrap initialization ... ok app-db_1 | syncing data to disk ... ok app-db_1 | app-db_1 | app-db_1 | Success. You can now start the database server using: app-db_1 | app-db_1 | pg_ctl -D /var/lib/postgresql/data -l logfile start app-db_1 | app-db_1 | initdb: warning: enabling "trust" authentication for local connections app-db_1 | initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. graph-db_1 | 2025-03-13 17:47:43.884+0000 INFO name: system graph-db_1 | 2025-03-13 17:47:43.884+0000 INFO creationDate: 2025-03-13T17:47:42.329Z graph-db_1 | 2025-03-13 17:47:43.884+0000 INFO Started. app-db_1 | waiting for server to start....2025-03-13 17:47:38.429 UTC [45] LOG: starting PostgreSQL 16.8 (Debian 16.8-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit bloodhound_1 | {"time":"2025-03-13T17:47:48.899385546Z","level":"INFO","message":"Executing SQL migrations for v6.2.0"} bloodhound_1 | {"time":"2025-03-13T17:47:48.901054366Z","level":"INFO","message":"Executing SQL migrations for v6.3.0"} bloodhound_1 | {"time":"2025-03-13T17:47:48.902174061Z","level":"INFO","message":"Executing SQL migrations for v6.4.0"} bloodhound_1 | {"time":"2025-03-13T17:47:48.90316274Z","level":"INFO","message":"Executing SQL migrations for v7.1.0"} bloodhound_1 | {"time":"2025-03-13T17:47:51.253488921Z","level":"INFO","message":"###################################################################"} bloodhound_1 | {"time":"2025-03-13T17:47:51.253508577Z","level":"INFO","message":"# #"} bloodhound_1 | {"time":"2025-03-13T17:47:51.253511713Z","level":"INFO","message":"# Initial Password Set To: GteFU7sIMGx3r5kx8Mn1hymZbDbH0rGv #"} bloodhound_1 | {"time":"2025-03-13T17:47:51.253514328Z","level":"INFO","message":"# #"} bloodhound_1 | {"time":"2025-03-13T17:47:51.253516582Z","level":"INFO","message":"###################################################################"} bloodhound_1 | {"time":"2025-03-13T17:47:53.626003415Z","level":"INFO","message":"Adding index azbase_system_tags_index to labels AZBase on properties system_tags using lucene+native-3.0"} bloodhound_1 | {"time":"2025-03-13T17:47:53.742655386Z","level":"INFO","message":"Adding index azwebapp_name_index to labels AZWebApp on properties name using lucene+native-3.0"} bloodhound_1 | {"time":"2025-03-13T17:47:53.77841472Z","level":"INFO","message":"Adding index adlocaluser_tenantid_index to labels ADLocalUser on properties tenantid using native-btree-1.0"} . . . [ snip ] . . .

❏ Acceder a BloodHound:

Abre tu navegador web y accede a la interfaz de BloodHound: http://localhost:8888.

Inicia sesión en BloodHound:

  • Usuario: admin
  • Contraseña: Es proporcionada la primera vez que se inicia el servicio y debe ser cambiada una vez que se haya iniciado sesión en la interfaz.

❏ Recopilar datos con SharpHound:

  • SharpHound es el recolector de datos oficial para BloodHound. Debes ejecutarlo en el entorno de Active Directory que deseas analizar.
  • Descarga SharpHound desde el repositorio oficial de BloodHound: SharpHound GitHub
Ejecuta SharpHound en un sistema unido al dominio con permisos suficientes para recopilar datos:

Esto generará archivos ZIP con los datos recopilados.

❏ Buscar caminos en BloodHound:

  • En la interfaz de BloodHound, haz clic en el botón "Upload Data" (Cargar datos).
  • BloodHound permite buscar caminos entre dos objetos (por ejemplo, un usuario y un grupo de administradores) para identificar posibles rutas de escalada de privilegios.
  • Busca por un usuario del dominio (por ejemplo: NU_1055@BLAZORIZED.HTB).
  • Haz clic en el objeto para seleccionarlo, en modo add to owned.
  • En el panel de detalles del objeto seleccionado, busca la sección "Outbound Control Rights" (Derechos de Control Salientes).
  • Utiliza la opción "Outbound Object Control", que es una relación clave en BloodHound, para identificar cómo un usuario o grupo puede tomar control sobre otros objetos en Active Directory.

En el siguiente enlace, se encuentra disponible un archivo zip diseñado específicamente para la ejecución de pruebas en un entorno de Active Directory. Este recurso ha sido meticulosamente elaborado para facilitar la simulación de escenarios complejos, permitiendo a los administradores y profesionales de TI evaluar la integridad, seguridad y rendimiento de sus implementaciones de Active Directory de manera controlada y precisa

Cuando termines de usar BloodHound, puedes detener y eliminar los contenedores con el siguiente comando: