githubixx.harden_linux
ansible-role-endure-linux
Este rol de Ansible fue creado principalmente para mi serie de blog Kubernetes de la manera fácil con Ansible - Endurecer las instancias. Pero también se puede usar de manera independiente para endurecer Linux. Tiene las siguientes características (algunas son opcionales):
- Agregar un usuario regular/desplegable para administración (por ejemplo, para Ansible o inicio de sesión via SSH)
- Ajustar intervalos de actualización de APT
- Configurar el firewall
UFW
y permitir solo acceso SSH por defecto (agregar más reglas/redes permitidas si lo deseas) - Ajustar configuraciones de seguridad en sysctl
- Ajustar configuraciones de
sshd
, por ejemplo, deshabilitar la autenticación de contraseña sshd, deshabilitar el inicio de sesión root vía sshd y deshabilitar sshd PermitTunnel - Instalar
sshguard
y ajustar la lista blanca - Cambiar la contraseña del usuario root
- Instalar/configurar
Sincronización de Tiempo de Red
(NTP), por ejemplo,openntpd
/ntp
/systemd-timesyncd
- Cambiar la configuración de
systemd-resolved
Versiones
Etiqueto cada lanzamiento y trato de seguir versionamiento semántico. Si deseas usar el rol, recomiendo chequear la última etiqueta. La rama maestra es básicamente desarrollo, mientras que las etiquetas marcan lanzamientos estables. Pero, en general, también intento mantener la rama maestra en buen estado.
Registro de Cambios
Historial de cambios:
Ver el CHANGELOG.md
Cambios recientes:
v8.2.0
- NUEVA CARACTERÍSTICA
- añadir soporte para Ubuntu 24.04
v8.1.0
OTROS
- actualizar comentarios sobre el uso de
mkpasswd
en lugar deansible
para crear una contraseña encriptada - Ubuntu: agregar tarea de autoremove
- actualizar el flujo de trabajo de Github
- actualizar comentarios sobre el uso de
MOLECULA
- usar
alvistack
en lugar de cajas Vagrantgenéricas
- usar diferentes direcciones IP
- usar
v8.0.0
RUPTURA/NUEVA CARACTERÍSTICA
- introducir variables
harden_linux_deploy_group
yharden_linux_deploy_group_gid
. Ambas son opcionales. Pero al menosharden_linux_deploy_group
debe ser especificado siharden_linux_deploy_user
también está establecido. Siharden_linux_deploy_group
se establece enroot
, no se cambiará nada. - si
harden_linux_deploy_user
se establece enroot
, no se cambiará nada. harden_linux_deploy_user
ahora es opcional. Si no se establece, no se configurará ningún usuario. También todas las variables que comienzan conharden_linux_deploy_user_
solo se utilizan si se especificaharden_linux_deploy_user
. Además, se añadió la variableharden_linux_deploy_user_home
.harden_linux_deploy_user_shell
,harden_linux_deploy_user_home
,harden_linux_deploy_user_uid
yharden_linux_deploy_user_password
ahora son opcionales. El directorio $HOME deharden_linux_deploy_user
solo se crea si se estableceharden_linux_deploy_user_home
.
- introducir variables
MOLECULA
- actualizar escenario de prueba para reflejar cambios de usuario/grupo de despliegue
Instalación
Descargar directamente desde Github (cambiar a la carpeta del rol de Ansible antes de clonar. Puedes averiguar la ruta del rol usando el comando
ansible-config dump | grep DEFAULT_ROLES_PATH
):git clone https://github.com/githubixx/ansible-role-harden-linux.git githubixx.harden_linux
A través del comando
ansible-galaxy
, y descargar directamente de Ansible Galaxy:ansible-galaxy install role githubixx.harden_linux
Crear un archivo
requirements.yml
con el siguiente contenido (esto descargará el rol de Github) e instalar conansible-galaxy role install -r requirements.yml
(cambiarversion
si es necesario):
---
roles:
- name: githubixx.harden_linux
src: https://github.com/githubixx/ansible-role-harden-linux.git
version: v8.1.0
Variables del Rol
Las siguientes variables no tienen valores por defecto. Debes especificarlas en un archivo en el directorio group_vars
o host_vars
. Por ejemplo, si estas configuraciones deben ser usadas solo para un host específico, crea un archivo para ese host llamado como el FQDN de ese host (por ejemplo host_vars/your-server.example.tld
) y coloca allí las variables con los valores correctos. Si quieres aplicar estas variables a un grupo de hosts, crea un archivo group_vars/your-group.yml
, por ejemplo, reemplaza your-group
con el nombre del grupo de hosts que creaste en el archivo de hosts de Ansible (no confundir con /etc/hosts...).
Si quieres establecer o cambiar la contraseña del usuario root
, establece la variable harden_linux_root_password
. Esto es opcional. Se espera una contraseña encriptada. Ansible no encriptará la contraseña por ti. Cómo crear una contraseña encriptada se describe en las Preguntas Frecuentes de Ansible. En Linux, el siguiente comando es probablemente el más confiable:
mkpasswd --method=sha-512
Para instalar un usuario que pueda ejecutar comandos con sudo
sin contraseña, establece las siguientes variables:
harden_linux_deploy_user: "un_usuario"
harden_linux_deploy_user_password: "una_contraseña"
harden_linux_deploy_user_home: "/home/un_usuario"
harden_linux_deploy_user_uid: "9999"
harden_linux_deploy_user_gid: "9999"
harden_linux_deploy_user_shell: "/bin/bash"
harden_linux_deploy_user
especifica el usuario que queremos utilizar para iniciar sesión en el host remoto. Como ya se mencionó, el rol harden_linux
deshabilitará el inicio de sesión del usuario root a través de SSH por una buena razón. Así que se necesita un usuario diferente. Este usuario tendrá permisos "sudo", los cuales son necesarios para Ansible (y/o tú mismo, por supuesto) para realizar su trabajo.
En harden_linux_deploy_user_password
se almacena la contraseña encriptada del usuario. Igual que con harden_linux_root_password
en cuanto a cómo crear una contraseña encriptada.
El directorio $HOME del usuario se especifica en harden_linux_root_password
. Para el UID y GID establece harden_linux_deploy_user_uid
y harden_linux_deploy_user_gid
. Nota: Si el usuario ya existe pero tiene un directorio home diferente, UID y/o GID, se cambiarán de acuerdo a las configuraciones anteriores. Esto también se aplica a harden_linux_deploy_user_shell
, que especifica la shell que debería usar el usuario después del inicio de sesión, por ejemplo.
harden_linux_deploy_user_public_keys
especifica una lista de archivos de claves públicas SSH que deseas agregar a $HOME/.ssh/authorized_keys
del usuario de despliegue en el host remoto. Si especificas /home/deploy/.ssh/id_rsa.pub
como valor aquí, el contenido de ese archivo local (presente en el nodo controlador de Ansible) se agregará a $HOME/.ssh/authorized_keys
del usuario desplegable en el host remoto.
harden_linux_optional_packages
(antes de la versión v6.0.0
de este rol, esta variable se llamaba harden_linux_required_packages
) especifica paquetes adicionales/opcionales para instalar en el host remoto. Por defecto, esta variable no está especificada. Por ejemplo:
harden_linux_optional_packages:
- vim
A diferencia de la variable anterior, harden_linux_absent_packages
desinstalará paquetes del sistema operativo en el host remoto. Por defecto, esta variable no está especificada. Por ejemplo:
harden_linux_absent_packages:
- vim
Las siguientes variables tienen valores por defecto. Así que solo necesitas cambiarlas si necesitas otro valor para esa variable. El rol cambia algunas configuraciones de sshd
por defecto:
harden_linux_sshd_settings:
"^PasswordAuthentication": "PasswordAuthentication no" # Deshabilitar autenticación por contraseña
"^PermitRootLogin": "PermitRootLogin no" # Deshabilitar inicio de sesión root por SSH
"^PermitTunnel": "PermitTunnel no" # Deshabilitar reenvío de dispositivo tun(4)
"^Port ": "Port 22" # Establecer puerto sshd
Personalmente, siempre cambio el puerto SSH por defecto ya que muchos ataques de fuerza bruta ocurren contra este puerto (pero, por supuesto, un escáner de puertos aún podrá detectarlo rápidamente). Así que si deseas cambiar la configuración del puerto, puedes hacerlo por ejemplo:
harden_linux_sshd_settings_user:
"^Port ": "Port 22222"
(Es importante notar el espacio en blanco después de ^Port
!). El playbook combinará harden_linux_sshd_settings
y harden_linux_sshd_settings_user
mientras que las configuraciones en harden_linux_sshd_settings_user
tienen preferencia, lo que significa que anularán la configuración de ^Port
en harden_linux_sshd_settings
. Como habrás notado, todas las claves en harden_linux_sshd_settings
y harden_linux_sshd_settings_user
comienzan con ^
. Eso es porque es una expresión regular (regex). Una de las tareas del playbook buscará una línea en /etc/ssh/sshd_config
, por ejemplo ^Port
(mientras que ^
significa "una línea que comienza con...") y reemplazará la línea (si se encuentra) con, por ejemplo, Port 22222
. Este enfoque hace que el playbook sea muy flexible para ajustar configuraciones en sshd_config
(básicamente puedes reemplazar cualquier configuración). Verás este patrón también para otras tareas. Así que todo lo mencionado aquí es cierto en tales casos.
A continuación algunas configuraciones por defecto del firewall/iptables. Las reglas y configuraciones del firewall/iptables son gestionadas por UFW:
harden_linux_ufw_defaults:
"^IPV6": 'IPV6=yes'
"^DEFAULT_INPUT_POLICY": 'DEFAULT_INPUT_POLICY="DROP"'
"^DEFAULT_OUTPUT_POLICY": 'DEFAULT_OUTPUT_POLICY="ACCEPT"'
"^DEFAULT_FORWARD_POLICY": 'DEFAULT_FORWARD_POLICY="DROP"'
"^DEFAULT_APPLICATION_POLICY": 'DEFAULT_APPLICATION_POLICY="SKIP"'
"^MANAGE_BUILTINS": 'MANAGE_BUILTINS=no'
"^IPT_SYSCTL": 'IPT_SYSCTL=/etc/ufw/sysctl.conf'
"^IPT_MODULES": 'IPT_MODULES="nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns"'
Estas configuraciones cambian básicamente los valores en /etc/defaults/ufw
. Para anular una o más de las configuraciones por defecto, puedes hacerlo especificando la misma clave (que es una regex) como arriba, por ejemplo, ^DEFAULT_FORWARD_POLICY
y simplemente asignarle el nuevo valor:
harden_linux_ufw_defaults_user:
"^DEFAULT_FORWARD_POLICY": 'DEFAULT_FORWARD_POLICY="ACCEPT"'
Como ya se mencionó, este playbook también combinará harden_linux_ufw_defaults
y harden_linux_ufw_defaults_user
, mientras que las configuraciones en harden_linux_ufw_defaults_user
tienen preferencia.
A continuación, podemos especificar algunas reglas de firewall con harden_linux_ufw_rules
. El valor por defecto es permitir tráfico SSH en el puerto 22
, que utiliza el protocolo tcp
:
harden_linux_ufw_rules:
- rule: "allow"
to_port: "22"
protocol: "tcp"
Los siguientes parámetros están disponibles con valores por defecto (si los hay):
rule (sin valor por defecto)
interface (valor por defecto '')
direction (valor por defecto 'in')
from_ip (valor por defecto 'any')
to_ip (valor por defecto 'any')
from_port (valor por defecto '')
to_port (valor por defecto '')
protocol (valor por defecto 'any')
log (valor por defecto 'false')
delete (valor por defecto 'false')
Una regla puede tener los valores allow
, deny
, limit
y reject
. El interface especifica la interfaz para la regla. La direction (in
o out
) utilizada para el interface
depende del valor de la dirección. from_ip especifica la dirección IP de origen y from_port el puerto de origen. to_ip especifica la dirección IP de destino y to_port el puerto de destino. protocol es any
por defecto. Los valores posibles son tcp
, udp
, ipv6
, esp
, ah
, gre
e igmp
. log puede ser false
(por defecto) o true
y especifica si las nuevas conexiones que coincidan con esta regla deben ser registradas. delete especifica si una regla debe ser eliminada. Esto es importante si se debe eliminar una regla previamente añadida. ¡Simplemente eliminar una regla de harden_linux_ufw_rules
no es suficiente! Debes usar delete
para eliminar esa regla.
También puedes permitir que hosts se comuniquen en redes específicas (sin restricciones de puerto), por ejemplo:
harden_linux_ufw_allow_networks:
- "10.3.0.0/24"
- "10.200.0.0/16"
A continuación, el rol harden_linux
también cambia algunas variables del sistema (sysctl.conf / sistema de archivos proc). Estas configuraciones son recomendaciones de Google que utilizan para sus imágenes de OS en Google Compute Cloud (ver Google Cloud - Requisitos para construir imágenes personalizadas y Configura tu imagen importada para Compute Engine). Estas son las configuraciones predeterminadas (si estás satisfecho con estas configuraciones, no necesitas hacer nada, pero recomiendo verificar si funcionan para tu configuración):
harden_linux_sysctl_settings:
"net.ipv4.tcp_syncookies": 1 # Habilitar protección contra ataques SYN
"net.ipv4.conf.all.accept_source_route": 0 # Ignorar paquetes con rutas de origen
"net.ipv6.conf.all.accept_source_route": 0 # IPv6 - Ignorar redireccionamientos ICMP
"net.ipv4.conf.default.accept_source_route": 0 # Ignorar paquetes con rutas de origen
"net.ipv6.conf.default.accept_source_route": 0 # IPv6 - Ignorar paquetes con rutas de origen
"net.ipv4.conf.all.accept_redirects": 0 # Ignorar redireccionamientos ICMP
"net.ipv6.conf.all.accept_redirects": 0 # IPv6 - Ignorar redireccionamientos ICMP
"net.ipv4.conf.default.accept_redirects": 0 # Ignorar redireccionamientos ICMP
"net.ipv6.conf.default.accept_redirects": 0 # IPv6 - Ignorar redireccionamientos ICMP
"net.ipv4.conf.all.secure_redirects": 1 # Ignorar redireccionamientos ICMP de hosts no GW
"net.ipv4.conf.default.secure_redirects": 1 # Ignorar redireccionamientos ICMP de hosts no GW
"net.ipv4.ip_forward": 0 # No permitir tráfico entre redes o actuar como enrutador
"net.ipv6.conf.all.forwarding": 0 # IPv6 - No permitir tráfico entre redes o actuar como enrutador
"net.ipv4.conf.all.send_redirects": 0 # No permitir tráfico entre redes o actuar como enrutador
"net.ipv4.conf.default.send_redirects": 0 # No permitir tráfico entre redes o actuar como enrutador
"net.ipv4.conf.all.rp_filter": 1 # Filtrado de ruta inversa - protección contra suplantación de IP
"net.ipv4.conf.default.rp_filter": 1 # Filtrado de ruta inversa - protección contra suplantación de IP
"net.ipv4.icmp_echo_ignore_broadcasts": 1 # Ignorar difusiones ICMP para evitar participar en ataques Smurf
"net.ipv4.icmp_ignore_bogus_error_responses": 1 # Ignorar errores ICMP inválidos
"net.ipv4.icmp_echo_ignore_all": 0 # Ignorar errores ICMP inválidos
"net.ipv4.conf.all.log_martians": 1 # Registrar paquetes falsificados, con rutas de origen, y redireccionamientos
"net.ipv4.conf.default.log_martians": 1 # Registrar paquetes falsificados, con rutas de origen, y redireccionamientos
"net.ipv4.tcp_rfc1337": 1 # Implementar arreglo RFC 1337
"kernel.randomize_va_space": 2 # Aleatorizar direcciones de mmap base, heap, stack y página VDSO
"fs.protected_hardlinks": 1 # Proteger contra carreras ToCToU
"fs.protected_symlinks": 1 # Proteger contra carreras ToCToU
"kernel.kptr_restrict": 1 # Dificultar la localización de direcciones del kernel
"kernel.perf_event_paranoid": 2 # Setear perf solo disponible para root
Puedes anular cada configuración individual, por ejemplo, creando una variable llamada harden_linux_sysctl_settings_user
:
harden_linux_sysctl_settings_user:
"net.ipv4.ip_forward": 1
"net.ipv6.conf.default.forwarding": 1
"net.ipv6.conf.all.forwarding": 1
Una de las tareas del playbook combinará harden_linux_sysctl_settings
y harden_linux_sysctl_settings_user
, mientras que nuevamente, las configuraciones de harden_linux_sysctl_settings_user
tienen preferencia. Consulta el archivo defaults/main.yml
del rol para más información sobre las configuraciones.
Si deseas activar el registro de UFW, establece:
harden_linux_ufw_logging: 'on'
Los valores posibles son on
, off
, low
, medium
, high
y full
.
A continuación, tenemos las configuraciones de "sshguard". "sshguard" protege contra ataques de fuerza bruta contra SSH. Para evitar bloquearte por un tiempo, puedes agregar IPs o rangos de IP a una lista blanca. Por defecto, básicamente es solo "localhost":
harden_linux_sshguard_whitelist:
- "127.0.0.0/8"
- "::1/128"
También se pueden instalar/configurar paquetes NTP. Esto es opcional. Por defecto, recomendaría usar systemd-timesyncd
. También puedes usar el paquete ntp
. Pero openntpd
y systemd-timesyncd
tienen la ventaja de que por defecto no escuchan en ningún puerto. Si solo deseas mantener la hora de los hosts sincronizada, esto es absolutamente suficiente. Tener la misma hora en todos tus hosts es crucial para algunos servicios. Por ejemplo, para la validación de certificados, para etcd, bases de datos, criptografía, etc.
Las opciones válidas para harden_linux_ntp
son:
- openntpd
- ntp
- systemd-timesyncd
openntpd
y systemd-timesyncd
tienen la ventaja de que por defecto no escuchan en ningún puerto como se mencionó. Si solo deseas mantener la hora de los hosts sincronizada, una de estas dos debería hacer el trabajo. systemd-timesyncd
ya está instalado si una distribución usa systemd
(lo cual es básicamente cierto para la mayoría de los sistemas operativos Linux en la actualidad). Así que en este caso no se necesitan paquetes adicionales. Para habilitar openntpd
, establece harden_linux_ntp
de acuerdo:
harden_linux_ntp: "openntpd"
Configuraciones para openntpd
, ntpd
o systemd-timesyncd
(ver próximo párrafo). Para más opciones consulta la página del manual: man 5 ntpd.conf
para ntp
y openntpd
y man 5 timesyncd.conf
para systemd-timesyncd
.
La "clave" aquí es una expresión regular de una configuración que deseas reemplazar y el valor es el nombre de la configuración + el valor de la configuración. Por ejemplo, queremos reemplazar la línea servers 0.debian.pool.ntp.org
con servers 1.debian.pool.ntp.org
. La regex (la clave) sería ^servers 0
, lo que significa:
"busca una línea en el archivo de configuración que comience con server 0
y reemplaza toda la línea con servers 1.debian.pool.ntp.org
". De esta manera, cualquier configuración en el archivo de configuración puede ser reemplazada por otra cosa. Algunos ejemplos:
harden_linux_ntp_settings:
"^servers 0": "servers 0.debian.pool.ntp.org"
"^servers 1": "servers 1.debian.pool.ntp.org"
"^servers 2": "servers 2.debian.pool.ntp.org"
"^servers 3": "servers 3.debian.pool.ntp.org"
Ten en cuenta: systemd-timesyncd
viene con configuraciones por defecto razonables en tiempo de compilación. Así que normalmente no hay necesidad de cambiar la configuración (ni siquiera los servidores NTP). Así que lo siguiente son solo ejemplos, pero realmente no necesitas especificar harden_linux_ntp_settings
para systemd-timesyncd
.
Para systemd-timesyncd
, el archivo de configuración es un poco diferente. En este caso, se creará un drop-in systemd para /etc/systemd/timesyncd.conf
en /etc/systemd/timesyncd.conf.d/
.
Ejemplo para Debian:
harden_linux_ntp_settings:
"^#NTP=": "NTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org"
Para Ubuntu:
harden_linux_ntp_settings:
"^#NTP=": "NTP=ntp.ubuntu.com"
Para Archlinux:
harden_linux_ntp_settings:
"^#NTP=": "NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org"
Con harden_linux_files_to_delete
se puede especificar una lista de archivos que deben estar ausentes en el host de destino, por ejemplo:
harden_linux_files_to_delete:
- "/root/.pw"
Si se usa systemd-resolved
para la resolución de DNS, su comportamiento se puede ajustar con harden_linux_systemd_resolved_settings
. Por defecto, esta variable no está especificada. Se creará una configuración drop-in de systemd en /etc/systemd/resolved.conf.d/99-override.conf
y las configuraciones especificadas se agregarán allí.
Nota: Si un parámetro en /etc/systemd/resolved.conf
ya está configurado (por ejemplo, DNS=8.8.8.8
), entonces configurar DNS=9.9.9.9
abajo se sumará. Esto significa que la configuración final será DNS=8.8.8.8 9.9.9.9
. Si no deseas eso, debes "anular" el valor primero y luego agregar el valor que deseas tener. Por ejemplo:
harden_linux_systemd_resolved_settings:
- DNS=
- DNS=9.9.9.9
Mientras que el servidor DNS de Google (8.8.8.8
, 8.8.4.4
) ofrece búsquedas DNS rápidas, es de alguna manera otra posibilidad para que Google pueda espiarte. Así que usar otros servidores DNS debería ser al menos algo en lo que pensar. Pero hay una cosa más y es cifrar las solicitudes DNS. Una de las maneras que systemd-resolved
soporta es DNSOverTLS
. Quad9 (9.9.9.9/149.112.112.112) y Cloudflare (1.1.1.1/1.0.0.1) soportan DNSOverTLS
.
Así que las siguientes configuraciones de systemd-resolved
configuran DNS de Quad9 y Cloudflare para IPv4 e IPv6. La configuración DNSOverTLS=opportunistic
usa DNSOverTLS
si el servidor DNS lo soporta y cae de vuelta a DNS sin cifrar regular si no se soporta (también consulta resolved.conf.5):
harden_linux_systemd_resolved_settings:
- DNS=
- DNS=9.9.9.9 1.1.1.1 2606:4700:4700::1111 2620:fe::fe
- FallbackDNS=
- FallbackDNS=149.112.112.112 1.0.0.1 2620:fe::9 2606:4700:4700::1001
- DNSOverTLS=
- DNSOverTLS=opportunistic
También se puede influir en el comportamiento de la memoria caché del gestor de paquetes. Por ejemplo, para Ubuntu:
# Establecer en "false" si no se debe actualizar la caché del paquete
harden_linux_ubuntu_update_cache: true
# Establecer tiempo válido de la caché del paquete
harden_linux_ubuntu_cache_valid_time: 3600
Para Archlinux:
# Establecer en "false" si no se debe actualizar la caché del paquete
harden_linux_archlinux_update_cache: true
Ejemplo de Playbook
Si instalaste el rol a través de ansible-galaxy install githubixx.harden_linux
, entonces incluye el rol en tu playbook como en este ejemplo:
- hosts: webservers
roles:
- githubixx.harden_linux
Pruebas
Este rol tiene un pequeño conjunto de pruebas que se crea utilizando Molecule, libvirt (vagrant-libvirt) y QEMU/KVM. Por favor, consulta mi publicación de blog Probando roles de Ansible con Molecule, libvirt (vagrant-libvirt) y QEMU/KVM para saber cómo configurarlo. La configuración de pruebas está aquí.
Después, se puede ejecutar molecule:
molecule converge
Esto configurará unas pocas máquinas virtuales (VM) con diferentes sistemas operativos Linux soportados y configurará el rol harden_linux
de acuerdo. También se incluye un pequeño paso de verificación:
molecule verify
Para limpiar, ejecuta
molecule destroy
Licencia
Licencia Pública General GNU Versión 3
Información del Autor
Ansible role for hardening Linux
ansible-galaxy install githubixx.harden_linux