5 formas de fortalecer un nuevo sistema con Ansible

Este artículo analiza algunas tareas de fortalecimiento comunes y cómo se pueden realizar de manera reproducible con Ansible. Proporciono un libro de jugadas de Ansible de ejemplo al final del artículo que puede ejecutar en sus sistemas en el primer arranque para reforzarlos. Puede expandir este libro de jugadas para incluir tareas adicionales de fortalecimiento a medida que las aprende.

Índice

Introducción

Cada administrador del sistema tiene una lista de verificación de las tareas relacionadas con la seguridad que realizan en cada sistema nuevo. Esta lista de verificación es un buen hábito, ya que garantiza que los servidores nuevos en su entorno cumplan con un conjunto de requisitos mínimos de seguridad. Sin embargo, hacer este trabajo manualmente también es lento y propenso a errores. Es fácil encontrarse con inconsistencias en la configuración debido a la serie de pasos manuales, y no hay forma de corregir la desviación de la configuración sin volver a ejecutar manualmente su lista de verificación.

Implementar su flujo de trabajo de seguridad en Ansible es una excelente manera de automatizar algunas "frutas al alcance de su mano" en su entorno. Este artículo describe algunos de los pasos básicos que tomo para fortalecer un nuevo sistema y le muestra cómo implementarlos usando Ansible. Las automatizaciones en este artículo no son abrumadoras; estas son probablemente cosas pequeñas que ya está haciendo para proteger sus sistemas. Sin embargo, la automatización de estas tareas garantiza que su infraestructura se configure de manera consistente y reproducible en su entorno.

Antes de comenzar, te mostraré rápidamente mi entorno para que me sigas. Estoy usando una estructura de directorio simple con un único libro de jugadas de Ansible (main.yml) y un host en mi inventario:

$ tree
.
├── files
│   └── etc
│       ├── issue
│       ├── motd
│       ├── ssh
│       │   └── sshd_config
│       └── sudoers.d
│           └── admin
├── inventory.ini
└── main.yml

4 directories, 6 files

$ cat inventory.ini
nyc1-webserver-1.example.com

software de parches

Lo primero que me gusta hacer en un sistema recién creado es asegurarme de que su software esté completamente parcheado. Se puede eliminar una cantidad increíble de superficie de ataque con solo estar atento a los parches. Ansible lo hace fácil. La tarea a continuación corrige completamente todos sus paquetes y se puede realizar fácilmente de forma regular usando cron (Donde Torre Ansibleen un entorno más grande):

- name: Perform full patching
  package:
    name: '*'
    state: latest

Acceso remoto seguro

Una vez que mi host está parcheado, aseguro rápidamente el acceso remoto a través de SSH. Primero, creo un usuario local con sudo permisos para que pueda desactivar el inicio de sesión remoto por parte del usuario root. Las siguientes tareas son solo un ejemplo y probablemente querrá personalizarlas para satisfacer sus necesidades:

- name: Add admin group
  group:
    name: admin
    state: present

- name: Add local user
  user:
    name: admin
    group: admin
    shell: /bin/bash
    home: /home/admin
    create_home: yes
    state: present

- name: Add SSH public key for user
  authorized_key:
    user: admin
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    state: present

- name: Add sudoer rule for local user
  copy:
    dest: /etc/sudoers.d/admin
    src: etc/sudoers.d/admin
    owner: root
    group: root
    mode: 0440
    validate: /usr/sbin/visudo -csf %s

Estas tareas agregan un usuario y grupo "administrador" local, agregan una clave pública SSH para el usuario y agregan un sudo regla para el usuario administrador que no permite contraseña sudo. La clave SSH será la misma clave pública para el usuario que ejecuta el libro de jugadas de Ansible localmente como se indica en el archivo. convocatoria de investigación.

Hay muchas formas de personalizar sshd para lograr sus objetivos de seguridad únicos, pero la publicación de mi colega sudoer Nate Lager es un buen comienzo. Específicamente, su artículo analiza las pautas de configuración (como deshabilitar la autenticación de contraseña) en el sshd archivo de configuración. Ansible se puede utilizar para crear una buena configuración conocida para todos los servidores de su entorno. Esto contribuye en gran medida a imponer una postura de seguridad coherente para uno de sus servicios más críticos, especialmente si se mantiene atento a la ejecución regular de Ansible en sus hosts.

Ansible copy El módulo se utiliza para colocar este archivo de configuración en sistemas remotos:

- name: Add hardened SSH config
  copy:
    dest: /etc/ssh/sshd_config
    src: etc/ssh/sshd_config
    owner: root
    group: root
    mode: 0600
  notify: Reload SSH

El archivo de configuración SSH que estoy usando está debajo. Este es principalmente un archivo predeterminado con algunos ajustes más, como deshabilitar la autenticación de contraseña y prohibir el inicio de sesión de root. Es probable que desarrolle sus propias mejores prácticas de archivo de configuración para satisfacer las necesidades de su organización, como permitir solo un conjunto específico de cifrados de confianza.

$ cat files/etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
AuthorizedKeysFile	.ssh/authorized_keys
PasswordAuthentication no
ChallengeResponseAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
UsePAM yes
X11Forwarding no
Banner /etc/issue.net
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem	sftp	/usr/libexec/openssh/sftp-server
PermitRootLogin no

PermitRootLogin no

Por último, tenga en cuenta que estoy usando un administrador para activar una actualización de la sshd un servicio. Este administrador está ubicado en el gerentes sección del libro de jugadas. Para obtener más información sobre gerentes y lo que hacen, miralo documentos.

handlers:
  - name: Reload SSH
    service:
      name: sshd
      state: reloaded

Una vez que haya bloqueado SSH desde una perspectiva de configuración, es hora de restringir SSH solo a las direcciones IP permitidas. Si está utilizando el valor predeterminado firewalldesto se hace fácilmente moviendo el servicio SSH al interno zona y establecer una lista de redes autorizadas. Ansible lo hace fácil con el firewalld módulo. Aquí un ejemplo:

- name: Add SSH port to internal zone
  firewalld:
    zone: internal
    service: ssh
    state: enabled
    immediate: yes
    permanent: yes

- name: Add permitted networks to internal zone
  firewalld:
    zone: internal
    source: "{{ item }}"
    state: enabled
    immediate: yes
    permanent: yes
  with_items: "{{ allowed_ssh_networks }}"

- name: Drop ssh from the public zone
  firewalld:
    zone: public
    service: ssh
    state: disabled
    immediate: yes
    permanent: yes

Esta tarea utiliza un con_articulos bucle con el permitir_ssh_redes variable. Esta variable se define en el vars sección del libro de jugadas:

vars:
  allowed_ssh_networks:
    - 192.168.122.0/24
    - 10.10.10.0/24

En este caso, el módulo restringe el acceso a la interno zona a las redes 10.10.10.0/24 y 192.168.122.0/24. el inmediato y permanente los parámetros le dicen al módulo que aplique las reglas inmediatamente y las agregue a firewalld's las reglas permanentes persisten al reiniciar. Puede confirmar la configuración viendo las reglas generadas. Para más información sobre firewalld y su configuración, ver el post firewalld de Enable Sysadmin.

[[email protected] ~]# firewall-cmd --list-all --zone=public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources: 
  services: dhcpv6-client
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
	
[[email protected] ~]# firewall-cmd --list-all --zone=internal
internal (active)
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 192.168.122.0/24 10.10.10.0/24
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Deshabilitar software y servicios no utilizados

Con el acceso a SSH bloqueado, me enfoco en eliminar el software no utilizado y deshabilitar los servicios innecesarios. Ansible package y service los módulos están a la altura del desafío, como se ve a continuación:

- name: Remove undesirable packages
  package:
    name: "{{ unnecessary_software }}"
    state: absent

- name: Stop and disable unnecessary services
  service:
    name: "{{ item }}"
    state: stopped
    enabled: no
  with_items: "{{ unnecessary_services }}"
  ignore_errors: yes

Hay dos cosas a tener en cuenta acerca de estas tareas. Primero, estoy usando variables (y bucles, para la tarea de servicio) nuevamente para mantener mi libro de jugadas breve y reutilizable. Estas variables se han añadido a la vars sección del libro de jugadas:

vars:
  allowed_ssh_networks:
    - 192.168.122.0/24
    - 10.10.10.0/24
  unnecessary_services:
    - postfix
    - telnet
  unnecessary_software:
    - tcpdump
    - nmap-ncat
    - wpa_supplicant

En segundo lugar, pongo ignore_errors en para la tarea de servicio. Esto evita que la ejecución del libro de jugadas falle si no existe un servicio en la máquina de destino (lo cual es aceptable). Por ejemplo, muchos servidores probablemente no tengan la telnet un servicio. Pero si lo hacen, quiero asegurarme de que esté apagado. Ignorando los errores, puedo ejecutar con éxito este libro de jugadas en un host, incluso si no tiene la telnet servicio instalado. Si está interesado en este enfoque, puede escribir condiciones más complejas para intentar deshabilitar un servicio solo si ya existe en el sistema remoto.

Mejoras en la política de seguridad

Ahora ha completado varias tareas muy concretas que mejoran la seguridad de su sistema recién aprovisionado. Lo último que me gusta hacer en mis sistemas no es mejorar la seguridad técnica, es el proceso y el control legal. Siempre me aseguro de que mis sistemas tengan uno y alerto a los usuarios sobre mi política de uso aceptable. Esto asegura que no haya duda de que el acceso a un sistema está restringido: está impreso directamente en el banner de inicio de sesión y MOTD.

La instalación de estos archivos es una actividad perfecta para Ansible. file módulo porque rara vez cambian en todos mis servidores. Para más discusiones sobre cuándo usar el file Donde copy módulo, vea mi artículo reciente.

- name: Set a message of the day
  copy:
    dest: /etc/motd
    src: etc/motd
    owner: root
    group: root
    mode: 0644

- name: Set a login banner
  copy:
    dest: "{{ item }}"
    src: etc/issue
    owner: root
    group: root
    mode: 0644
  with_items:
    - /etc/issue
    - /etc/issue.net

El contenido de los archivos reales es una explicación simple y concisa del acceso permitido y el uso aceptable. Querrá trabajar con el equipo legal de su empresa para asegurarse de que el mensaje sea adecuado para su organización.

$ cat files/etc/issue
Use of this system is restricted to authorized users only, and all use is subjected to an acceptable use policy.

IF YOU ARE NOT AUTHORIZED TO USE THIS SYSTEM, DISCONNECT NOW.

$ cat files/etc/motd
THIS SYSTEM IS FOR AUTHORIZED USE ONLY

By using this system, you agree to be bound by all policies found at https://wiki.example.com/acceptable_use_policy.html. Improper use of this system is subject to civil and legal penalties.

All activities are logged and monitored.

Conclusión

Este artículo le muestra cómo consolidar múltiples tareas de fortalecimiento de servidores en un solo libro de jugadas de Ansible para ejecutar en nuevos sistemas (y continuar ejecutándose en sistemas existentes) para mejorar su seguridad. Al tomar algunos de los consejos que aprendió y combinarlos con su propio runbook de seguridad, puede usar Ansible para garantizar configuraciones de seguridad rápidas, fáciles y repetibles en su entorno. Esta es una excelente manera para que los principiantes de Ansible comiencen a automatizar un flujo de trabajo común. También es una excelente manera para que el usuario avanzado de Ansible aproveche su herramienta favorita para mejorar la seguridad de su organización.

El libro de jugadas completo utilizado en este artículo se incluye a continuación:

---

- hosts: all
  vars:
    allowed_ssh_networks:
      - 192.168.122.0/24
      - 10.10.10.0/24
    unnecessary_services:
      - postfix
      - telnet
    unnecessary_software:
      - tcpdump
      - nmap-ncat
      - wpa_supplicant
  tasks:
    - name: Perform full patching
      package:
        name: '*'
        state: latest

    - name: Add admin group
      group:
        name: admin
        state: present

    - name: Add local user
      user:
        name: admin
        group: admin
        shell: /bin/bash
        home: /home/admin
        create_home: yes
        state: present

    - name: Add SSH public key for user
      authorized_key:
        user: admin
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
        state: present

    - name: Add sudoer rule for local user
      copy:
        dest: /etc/sudoers.d/admin
        src: etc/sudoers.d/admin
        owner: root
        group: root
        mode: 0440
        validate: /usr/sbin/visudo -csf %s

    - name: Add hardened SSH config
      copy:
        dest: /etc/ssh/sshd_config
        src: etc/ssh/sshd_config
        owner: root
        group: root
        mode: 0600
      notify: Reload SSH

    - name: Add SSH port to internal zone
      firewalld:
        zone: internal
        service: ssh
        state: enabled
        immediate: yes
        permanent: yes

    - name: Add permitted networks to internal zone
      firewalld:
        zone: internal
        source: "{{ item }}"
        state: enabled
        immediate: yes
        permanent: yes
      with_items: "{{ allowed_ssh_networks }}"

    - name: Drop ssh from the public zone
      firewalld:
        zone: public
        service: ssh
        state: disabled
        immediate: yes
        permanent: yes

    - name: Remove undesirable packages
      package:
        name: "{{ unnecessary_software }}"
        state: absent

    - name: Stop and disable unnecessary services
      service:
        name: "{{ item }}"
        state: stopped
        enabled: no
      with_items: "{{ unnecessary_services }}"
      ignore_errors: yes

    - name: Set a message of the day
      copy:
        dest: /etc/motd
        src: etc/motd
        owner: root
        group: root
        mode: 0644

    - name: Set a login banner
      copy:
        dest: "{{ item }}"
        src: etc/issue
        owner: root
        group: root
        mode: 0644
      with_items:
        - /etc/issue
        - /etc/issue.net

  handlers:
    - name: Reload SSH
      service:
        name: sshd
        state: reloaded

Artículos de interés

Subir