Schlagwort-Archive: Red Hat

RHEL Spiegelserver für arme Admins

Es muss nicht immer gleich der Red Hat Sattelite Server sein, um einen lokalen Spiegelserver für die Installation von RPM-Paketen bereitzustellen.

Auf GitHub habe ich im Repository „Poor man’s RHEL mirror“ eine kleine Sammlung von Bash-Skripten zusammengestellt, mit denen sich ein Spiegelserver für RHEL-Repositories aufbauen lässt. Mit diesem können RHEL-Repositories, für welche man eine gültige Subskription besitzt, auf einen Host im lokalen Netzwerk synchronisiert und deren Pakete anderen RHEL-Servern im LAN zur Verfügung gestellt werden.

Neben der reinen Spiegelung können mit den auf GitHub bereitgestellten Skripten weitere lokale Stage-Repositories eingerichtet werden, mit denen sich die Verfügbarkeit von Paketen für einzelne Stages steuern lässt. Zusätzlich bietet das Projekt Skripte, um eigene YUM-Repositories zu erstellen, um zum Beispiel eigene Pakete darüber bereitstellen zu können. Des Weiteren wurde die Möglichkeit berücksichtigt, die Red Hat Errata Informationen in die lokalen RHEL-Repositories zu integrieren, um die --advisory Option für YUM auch auf Systemen nutzen zu können, die über keine eigene Verbindung zum Internet verfügen.

Warum ist dieses Projekt nützlich?

  • Es schont die eigene Internetverbindung, da Pakete nur einmal aus dem Internet heruntergeladen und anschließend im LAN zur Verfügung gestellt werden.
  • Es unterstützt bei der Erstellung eines YUM-Repositories zur Bereitstellung von RPM-Paketen.
  • Es unterstützt das Staging-Konzept, in dem es die Möglichkeit bietet, stage-spezifische Repositories bereitzustellen.
  • Es implementiert die Red Hat Errata Informationen in die gespiegelten RHEL-Repos, so dass diese von angebundenen Servern genutzt werden können, die über keine eigene Internetverbindung verfügen.
  • Es entstehen keine Zusatzkosten, da alle notwendigen Werkzeuge in den Repos einer RHEL-Standard-Subskription enthalten sind.

Wer kann dieses Projekt nutzen?

Das Projekt selbst steht unter der MIT-Lizenz und kann unter deren Bedingungen frei genutzt, modifiziert und weiter verteilt werden.

Für den Betrieb des Spiegelservers ist der Besitz einer gültigen RHEL-Subskription Voraussetzung. Denn es können nur jene Repos gespiegelt werden, für die eine gültige Subskription vorhanden ist. Auch alle an den Spiegelserver angeschlossenen Systeme müssen über eine entsprechende und gültige Subskription verfügen.

Bei Fragen zu Subskriptionen helfen die folgenden Seiten weiter:

Um mit diesem Projekt einen Spiegelserver aufsetzen und betreiben zu können, sind gewisse Kenntnisse erforderlich. Zu diesen zählen die Installation eine RHEL-Systems inkl. Registrierung, das Hinzufügen von Subskriptionen und die Installation von Paketen. Informationen hierzu bietet die Product Documentation for Red Hat Enterprise Linux 7.

Wie ist das GitHub-Repository zu diesem Projekt aufgebaut?

Das GitHub-Repository beinhaltet ein README, welches einen Überblick über das Projekt und eine Kurzbeschreibung der einzelnen Skripte in englischer Sprache beinhaltet. Im Master-Branch befindet sich die letzte stabile Version des Projekts. Weiterentwicklungen und Fehlerkorrekturen werden im Dev-Branch gepflegt und nach einer Testphase in den Master-Branch übernommen.

Sorgen, Nöte und Anträge sowie gefundene Fehler dürfen gern über die Issue-Funktion oder in den Kommentaren zu diesem Beitrag gemeldet werden.

An dieser Stelle folgt eine Beschreibung in deutscher Sprache, wie ein Spiegelserver mit diesem Projekt aufgebaut werden kann. Dabei handelt es sich um keine Schritt-für-Schritt-Anleitung und es werden grundlegende Kenntnisse über den Betrieb eines RHEL-Servers und die Installation sowie Konfiguration von Paketen vorausgesetzt.

Einrichtung eines Spiegelservers für arme Sysadmins

Um das Projekt nutzen zu können, benötigt man eine RHEL-Installation mit gültiger Subskription, auf welcher mindestens die folgenden Pakete installiert sein müssen:

  • reposync und createrepo, um RHEL-Repos synchronisieren und eigene Repos erstellen zu können
  • git zum Klonen des hier beschriebenen Projekts
  • Die Gruppe Basic Web Server oder einen anderen Webserver eurer Wahl, um die gespiegelten Repos über HTTP im LAN bereitstellen zu können

Zu Beginn sind die Dateien aus dem oben genannten GitHub-Repository in einem Verzeichnis auf dem lokalen Host bereitzustellen. Anschließend ist das Projekt zu konfigurieren. Die dazu notwendigen Schritte werden in den folgenden Abschnitten erläutert.

CONFIG.SAMPLE

Hierbei handelt es sich um die Hauptkonfigurationsdatei. Diese ist in CONFIG umzubenennen bzw. zu kopieren und zu editieren. In dieser Datei werden die Variablen gesetzt, die von den verschiedenen Shell-Skripten verwendet werden. Darunter sind z.B. Angaben, welche Repos gespiegelt werden und wo die Dateien gespeichert werden sollen.

Die Datei ist mit Kommentaren versehen und sollte weitgehend selbsterklärend sein (was für alle weiteren Dateien gilt).

create_yum_repo.sh

Dieses Skript kann genutzt werden, um ein eigenes YUM-Repository zu erstellen, über welches RPM-Pakete bereitgestellt werden können. Der Name des zu erstellenden Repos kann dem Skript als Parameter übergeben werden.

do_reposync.sh

Dies ist das Herzstück des Projekts. Es kümmert sich um die Spiegelung der RHEL-Repos. Die notwendigen Parameter werden in der Datei CONFIG konfiguriert.

Das Skript lädt nur die aktuellen Pakete aus den Repos herunter, löscht aus den Upstream-Repos entfernte Pakete jedoch nicht automatisch auf dem lokalen Host. Dies ist meinen persönlichen Anforderungen geschuldet. Es ist nicht ausgeschlossen, dass ich diese Parameter in Zukunft ebenfalls konfigurierbar gestalte.

Einen Überblick über den Speicherbedarf ausgewählter RHEL-Repos findet ihr hier: How much disk space do I need for reposync?

Um die heruntergeladenen Pakete im LAN zur Verfügung zu stellen, muss das BASEDIR (siehe CONFIG) über einen Webserver zugreifbar gemacht werden.

refresh_repo.sh

Werden einem Repo neue RPM-Dateien hinzugefügt, muss die Metadaten-Datenbank aktualisiert werden, damit Klienten die neuen Pakete auch finden können. Um diese Aktualisierung kümmert sich eben dieses Skript.

rsync_repo.sh

Mit diesem Skript lassen sich Repos auf dem lokalen System synchronisieren. Dabei werden die Dateien jedoch nicht 1:1 kopiert, sondern Hardlinks erstellt. Dies spart bei der Verwendung mehrerer Repos für unterschiedliche Stages Speicherplatz.

Neben dem kompletten Sync eines Repos ist es auch möglich, dem Skript eine Datei zu übergeben, welche die Namen der Pakete enthält, welche in ein weiteres Repo „transportiert“ werden sollen.

Wrapper-Scripts

In meiner Umgebung arbeiten wir mit bis zu vier verschiedenen Stages (E, I, Q und P). Für jede dieser Stages wird ein eigenes Stage-Repo des Upstream rhel-7-server-rpms erzeugt. Um diese Stage-Repos zu aktualisieren, werden die folgenden Skripte verwendet:

  • update_rhel-e-stage.sh
  • update_rhel-i-stage.sh
  • update_rhel-q-stage.sh
  • update_rhel-p-stage.sh

Jede Stage wird mit den Paketen aus der vorhergehenden aktualisiert. So ruft z.B. update_rhel-e-stage.sh das Skript rsync_repo.sh, um die Pakete aus dem lokalen Spiegel des Upstreams rhel-7-server-rpms zu importieren. update_rhel-i-stage.sh verwendet dementsprechend die rhel-e-stage als Quelle usw.

Diese Konfiguration ist für meinen Anwendungsfall optimiert. Die Verwendung der Skripte ist optional. Der Spiegelserver funktioniert auch ohne diese Wrapper-Scripts.

update_mirror_packages_and_erratas.sh

Dieses Skript aktualisiert die Pakete in den Repos des lokalen Spiegelservers inkl. der Red Hat Errata Informationen. Letztere ermöglichen es, die Erratas (RHSA, RHBA und RHEA) auch Systemen verfügbar zu machen, welche über keine Verbindung zum Internet verfügen.

Das Skript ist in der Standardeinstellung auf meinen Anwendungsfall optimiert und aktualisiert am Ende alle vorhandenen RHEL-Stage-Repos. Wer diese Funktion nicht benötigt, kann sie durch Auskommentieren der Zeilen 45 und 46 im Skript deaktivieren.

Anschließend kann ein Cronjob erstellt werden, welcher das Skript ausführt, um den Spiegelserver regelmäßig gemäß der eigenen Anforderungen zu aktualisieren.

Die gespiegelten Repos verfügbar machen

Hat man die Repos seiner Wahl gespiegelt, ergibt sich je nach Konfiguration eine Verzeichnisstruktur ähnlich der folgenden.

$ tree -L 2
.
├──  rhel-7-test-mirror
│   ├── rhel-7-server-extras-rpms
│   ├── rhel-7-server-optional-rpms
│   ├── rhel-7-server-rpms
│   ├── rhel-7-server-supplementary-rpms
│   ├── rhel-e-stage
│   ├── rhel-e-stage.repo
│   ├── rhel-i-stage
│   ├── rhel-p-stage
│   ├── rhel-q-stage
│   └── rhel-server-rhscl-7-rpms

Das Verzeichnis rhel-7-test-mirror aus obigen Beispiel enthält die gespiegelten Repos als Unterverzeichnisse. Dieses Verzeichnis sollte über einen Webserver zugreifbar gemacht werden, um die Pakete den Clients im lokalen Netzwerk verfügbar zu machen.

Im obigen Listing ist eine Datei namens rhel-e-stage.repo zu sehen. Dabei handelt es sich um eine Repo-Datei, welche heruntergeladen und im Verzeichnis /etc/yum.repos.d/ platziert werden kann, um wie in diesem Beispiel das Repo rhel-e-stage zu aktivieren.

Aufbau einer Repo-Datei

Das folgende Listing zeigt die kommentierte Repo-Datei aus dem vorstehenden Abschnitt. Sie kann als Muster für weitere eigene Repo-Dateien dienen.

[rhel-e-stage] # Repo ID
baseurl = http://example.com/rhel-7-test-mirror/rhel-e-stage/
gpgcheck = 1
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
name = Repo for rhel-7-server-rpms (Test)

Fragen, Sorgen, Nöte und Anträge

Das Projekt und die enthaltene Software werden so wie sie sind unter der angegebenen Lizenz zur Verfügung gestellt.

Fragen, Sorgen, Nöte und Anträge können sowohl hier in den Kommentaren zum Artikel, als auch auf Github hinterlassen werden.

Ich hoffe, dass dieses Projekt euch (weiterhin) nützlich ist und freue mich über Rückmeldungen, wie es euch gefällt.

Ansible: Patch-Management für Red Hat Systeme

Als Linux-Distribution für den Betrieb im Rechenzentrum fiel unsere Wahl vor einiger Zeit auf Red Hat Enterprise Linux. Zu meinen Aufgaben gehört es, ein Patch-Management für diese Systeme zu entwickeln, welches die folgenden Anforderungen erfüllt:

  1. Die zu aktualisierenden Hosts werden in Gruppen im Ansible Inventory verwaltet. Eine Gruppe entspricht dabei einer Stage/Phase für das Patch-Management.
  2. An definierten Stichtagen sollen automatisiert fehlende Sicherheitsaktualisierungen auf den Systemen in den verschiedenen Stages/Phasen eingespielt werden können.
  3. Dabei sollen ausschließlich Pakete aktualisiert werden, für die Red Hat Security Advisory veröffentlicht wurden.
  4. Wenn Pakete aktualisiert wurden, soll der Host anschließend neugestartet werden.

Ich habe mich entschieden, diese Anforderungen durch die Verwendung von Ansible zu erfüllen. Wem Ansible noch kein Begriff ist, möge einen Blick in die Quellen am Ende des Artikels werfen.[1. Ansible – IT-Automation für Jedermann] [2. Ansible Documentation {en}] [3. Linux-Benutzerkonten mit Ansible verwalten] [4. Das Modul yum_repository] [5. Die Module copy und cron]

Mit den Anregungen meines Arbeitskollegen habe ich dazu das folgende Playbook erstellt, welches die Rolle rhel-patchmanagement auf allen Hosts mit einem Red Hat Betriebssystem ausführt:

---
- hosts: all

  tasks:
    - name: Group by OS
      group_by: key=os_{{ ansible_distribution }}
      changed_when: False

- hosts: os_RedHat
  roles:
    - rhel-patchmanagement

Die Rolle rhel-patchmanagement besteht aus den beiden folgenden Dateien:

  • roles/patch_rhel/tasks/main.yml
  • roles/patch_rhel/vars/main.yml

roles/patch_rhel/vars/main.yml:

---
rhsa_to_install: RHSA-2016:1626,RHSA-2016:1628,RHSA-2016:1633

Obiges Listing gibt ein kurzes Beispiel, wie die Red Hat Security Advisory (RHSA) Nummern einer Variablen zugewiesen werden können. Die Variable rhsa_to_install wird dann in der Task-Datei verwendet.

roles/patch_rhel/tasks/main.yml:

---
  - name: Install Red Hat Security Advisory (RHSA)
    command: yum -y update-minimal --advisory {{ rhsa_to_install }}
    register: yum_output
  - debug: var=yum_output

  - name: Reboot Host if packages were updated
    shell: sleep 2 && shutdown -r now "Ansible updates triggered"
    async: 1
    poll: 0
    ignore_errors: true
    when: ('"Complete!" in "{{ yum_output.stdout_lines[-1] }}"') or
          ('"Komplett!" in "{{ yum_output.stdout_lines[-1] }}"')

  - name: waiting for access server
    local_action: wait_for
      host={{ inventory_hostname }}
      state=started
      port=22
      delay=30
      timeout=300
      connect_timeout=15

Zuerst wird das Kommando zur Aktualisierung der zu den angegebenen RHSA gehörenden Pakete auf den Hosts ausgeführt. Dabei wird die Ausgabe des Kommandos yum auf den Hosts der Variable yum_output zugewiesen.[6. Registered Variables] Diese Variable wird im nächsten Schritt ausgewertet, um zu ermitteln, ob Pakete aktualisiert wurden. Ist dies der Fall, wird der Host neugestartet.

Erklärung: Wurden Pakete aktualisiert, steht in der letzten Zeile der YUM-Ausgabe der Ausdruck „Complete!“. "{{ yum_output.stdout_lines[-1] }}" dereferenziert die Variable und liefert die Ausgabe des YUM-Kommandos als Liste zurück. Dabei wird in diesem Fall auf das letzte Element der Liste zugegriffen. Enthält diese Zeile den genannten Ausdruck, wird der Host neugestartet. Hinweis: Die zweite Zeile der when-Bedingung aus dem oberen Listing dient der Behandlung einer deutschsprachigen Ausgabe. In diesem Fall wird das Schlüsselwort „Komplett!“ ausgegeben und in der Variable gespeichert.

Der letzte Task wartet 30 Sekunden ab, um dem Host Zeit für den Neustart zu geben und prüft, ob eine Verbindung hergestellt werden kann. Damit soll sichergestellt werden, dass der Host nach dem Neustart wieder korrekt hochfährt.

Damit sind die Anforderungen aus Punkt 2 und 3 erfüllt. Um auch noch die Anforderung aus Punkt 1 zu erfüllen, setze ich folgendes Wrapper-Skript ein, welches das Playbook zu den definierten Stichtagen ausführen soll:

#!/bin/sh

DOM=`date +%d`
DOW=`date +%w`
LOG="/var/log/ansible/patch_run_`date +%Y-%m-%d`.log"
SETUP_LOG="/var/log/ansible/setup_patch_run_`date +%Y-%m-%d`.log"
SSH_KEY="/pfad/zum/ssh-key"
PLAYBOOK="/data/ansible/patch_rhel.yml"
CREATEVARS="/pfad/zu/roles/rhel-patchmanagement/create_vars.sh"

# Run Patch-Management ad-hoc in the specified phase.
# Example: './run_rhel_patch_mgmt.sh NOW rhel-patch-phase1'
if [ "${1}" = "NOW" ] && [ -n "${2}" ]
then
  ansible-playbook $PLAYBOOK --private-key=$SSH_KEY --limit="${2}" >>$LOG 2>&1
  exit
fi

if [ "${1}" = "NOW" ] && [ -z "${2}" ]
then
  echo "ERROR: Second argument is missing."
  echo "Example: './run_rhel_patch_mgmt.sh NOW rhel-patch-phase1'"
  exit
fi

# Setup the next patchcycle
if [ "$DOW" = "2" ] && [ "$DOM" -gt 0 ] && [ "$DOM" -lt 8 ]
then
    $CREATEVARS > $SETUP_LOG 2>&1
fi

# Patchcycle of the rhel-patch-phase1 on the second Tuesday of a month
if [ "$DOW" = "2" ] && [ "$DOM" -gt 7 ] && [ "$DOM" -lt 15 ]
then
    ansible-playbook $PLAYBOOK --private-key=$SSH_KEY --limit=rhel-patch-phase1 > $LOG 2>&1
fi

# Patchcycle of the rhel-patch-phase2 on the third Tuesday of a month
if [ "$DOW" = "2" ] && [ "$DOM" -gt 14 ] && [ "$DOM" -lt 22 ]
then
    ansible-playbook $PLAYBOOK --private-key=$SSH_KEY --limit=rhel-patch-phase2 > $LOG 2>&1
fi

# Patchcycle of the rhel-patch-phase3 on the fourth Tuesday of a month
if [ "$DOW" = "2" ] && [ "$DOM" -gt 21 ] && [ "$DOM" -lt 29 ]
then
    ansible-playbook $PLAYBOOK --private-key=$SSH_KEY --limit=rhel-patch-phase3 > $LOG 2>&1
fi

# Patchcycle of the rhel-patch-phase4 on the fourth Wednesday of a month
if [ "$DOW" = "3" ] && [ "$DOM" -gt 21 ] && [ "$DOM" -lt 30 ]
then
    ansible-playbook $PLAYBOOK --private-key=$SSH_KEY --limit=rhel-patch-phase4 > $LOG 2>&1
fi

Mit diesem Wrapper-Skript möchte ich dafür sorgen, dass an jedem 2. Dienstag im Monat die RSHA-Aktualisierungen auf den Hosts in der rhel-patch-phase1, jeden 3. Dienstag in der rhel-patch-phase2, jeden 4. Dienstag in der rhel-patch-phase3 und jeden 4. Mittwoch in rhel-patch-phase4 installiert werden.

So kann sichergestellt werden, dass die Informationen aus den RHSA alle Hosts erreichen. Gleichzeitig wird den Betreibern der Hosts die Gelegegnheit gegeben, die Aktualisierungen bis zu den genannten Stichtagen selbst einzuspielen. Damit sollte ich auch an Punkt 1 einen Haken dran machen können.

Die Ansible-Rolle und dazugehörende Skripte und Beispiel-Dateien findet ihr auf:

Fragen zur Anwendung, Konfiguration und Nutzung des RHEL-Patchmanagements könnt ihr gerne auf GitHub oder hier in den Kommentaren stellen.

Aktualisiert am: 07.09.2018