Deploying Meltdown and Spectre Fixes with Ansible on Linux Hosts

in meltdown •  7 years ago  (edited)

Spectre & Meltdown Logos

As it stands the current "fixes" for Meltdown and Spectre mainly involve updating and upgrading hosts to include their patched kernel upgrades. When it comes to applying the updates to multiple Linux servers, one approach is to use the playbook/plays in this "lockdown" repo from Ansible.

https://github.com/ansible/ansible-lockdown/blob/master/meltdown-spectre-linux.yml

This is how the YAML works to patch the aforementioned exploits.

First off for the hosts directive, either the default all hosts is used or any hosts provided -i when running ansible-playbook take precedence. The tasks are to be carried out with become: and thereby super user privileges.

# https://meltdownattack.com

- name: Patch Linux systems against Meltdown and Spectre
  hosts: "{{ target_hosts | default('all') }}"
  become: yes

Variables are defined ready for use later on in the tasks section.

reboot_after_update: is set to no but should be set to "yes" where possible by yourself. The reason for this is covered properly towards the end of these explanations.

packages: contains the required kernel package versions for each respective Linux distro. Most of the Debian/Ubuntu entries are empty with the exception of Debian 9 (the latest stable version) which contains the specific kernel package.

The empty values may be updated by the maintainers at some point, but you can add in the kernel packages yourself for the empty ones. I've done this in the next code snippet, from the information given at these two links:

https://www.debian.org/security/2018/dsa-4078
https://wiki.ubuntu.com/SecurityTeam/KnowledgeBase/SpectreAndMeltdown

These kernel packages are in essence the only Meltdown and or Spectre "fixes" currently available.

  vars:
    reboot_after_update: no
    packages:
      # https://access.redhat.com/security/vulnerabilities/speculativeexecution
      RedHat7:
        - kernel-3.10.0-693.11.6.el7
        - microcode_ctl-2.1-22.2.el7
        - perf-3.10.0-693.11.6.el7
        - python-perf-3.10.0-693.11.6.el7
      RedHat6:
        - kernel-2.6.32-696.18.7.el6
        - kernel-firmware-2.6.32-696.18.7.el6
        - perf-2.6.32-696.18.7.el6
        - python-perf-2.6.32-696.18.7.el6

      # https://www.debian.org/security/2018/dsa-4078
      Debian7:
        - linux-image-3.2.0-5-amd64
      Debian8:
        - linux-image-3.16.0-5-amd64
      Debian9:
        - linux-image-4.9.0-5-amd64

      # https://wiki.ubuntu.com/SecurityTeam/KnowledgeBase/SpectreAndMeltdown
      Ubuntu14:
        - linux-image-3.13.0-141-generic
      Ubuntu16:
        - linux-image-4.4.0-112-generic 
      Ubuntu17:
        - linux-image-4.13.0-31-generic 

Note: Please remember that this is as things stand right now with the kernel patching in late January, so these version numbers are always subject to change as new fixes are released.

There are two tasks in total. One for each type of package manager in use on the various distros.

When Yum is detected on the host by Ansible, the first task is executed and the distro packages defined previously are referenced for installation. This is done using the ansible_os_family and ansible_distribution_major_version system fact variables - the distro name and version number respectively.

A handler is then called to reboot the host (explained later on).

  tasks:
    - name: RHEL | Install kernel updates
      yum:
        name: "{{ packages[ansible_os_family ~ ansible_distribution_major_version] }}"
        state: present
      when: ansible_pkg_mgr == 'yum'
      notify: reboot system

If Aptitude (apt) is detected on the host in place of Yum, the second task is run instead. Which uses a similar process. The distro type and version number are sourced from the start in order to install the correct packages (like in the other task), whilst the package index is updated via update_cache:.

As before the host is then rebooted via the handler (more on that now, as promised).

    - name: DEBIAN | Install kernel updates
      apt:
        name: "{{ item }}"
        state: present
        update_cache: yes
        cache_valid_time: 3600
      with_items: "{{ packages[ansible_distribution ~ ansible_distribution_major_version] }}"
      when: ansible_pkg_mgr == 'apt'
      notify: reboot system

If the variable reboot_after_update from the start is set to yes or true. The host(s) will reboot at the end of each task run, as the handler is called.

This is here as it's necessary to reboot the system to begin using the new kernel changes brought in for the Spectre/Meltdown exploits. So you should set reboot_after_update to "yes" at the start of the file, as long as it's safe to do so in terms of node availability and uptime.

Lastly async: allows the shutdown command to run for a maximum of 15 seconds, but also poll: tells Ansible to check constantly for its completion. This is all so Ansible moves on and doesn't idle from the node's system shutdown.

  handlers:
    - name: reboot system
      shell: sleep 3; reboot
      async: 15
      poll: 0
      when: reboot_after_update

It might be better to download the repository itself but if you want the meltdown-spectre-linux.yml file I showed here (with all the kernel package versions added in) use this Gist instead:

https://gist.github.com/5car1z/ddbb17cb763d5aedf129732213febac4

Warning: Be aware that the "reboot" variable is set to yes in this Gist.

Run the file against your desired host groups or host patterns as normal, adding a -K sudo password or -u user switch if relevant e.g.

$ ansible-playbook -l webservers meltdown-spectre-linux.yml -K

Then watch Ansible check and update the kernel packages on each host. Oh and uname -r reveals the kernel package in use by your current node.

Thanks to Sam Doran for the plays and the Ansible repository this is taken from.


Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!