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