Überprüfen von sudoers.d-Dateien mit Ansible

Überprüfen von sudoers.d-Dateien mit Ansible

Ich habe ein Ansible-Playbook, mit dem ich unsere Sudoers-Dateien in unserer Umgebung verwalte. Wir möchten eine minimale Sudoers-Datei unter /etc/sudoers aufbewahren und alles, was wir hinzufügen möchten, in separate Dateien unter /etc/sudoers.d einfügen.

Mein Ansible-Playbook enthält die folgende Aufgabe zum Pushen dieser Dateien:

- name: copy sudoers files
  copy:
    src: "{{ item }}"
    dest: "/etc/sudoers.d/{{ item }}"
    backup: yes
    owner: root
    group: root
    mode: 0440
    validate: /usr/sbin/visudo -cf %s
  with_items:
    - admins
    - apache
    - monitor

Die Aufgabe enthält eine Validierungsklausel, um sicherzustellen, dass die Datei gültig ist, bevor sie übermittelt wird. Dies hat im Allgemeinen gut funktioniert. Heute bin ich jedoch auf ein Problem gestoßen, bei dem ein Update sudo beschädigt hat. Die Datei hat den Validierungsschritt bestanden, enthielt jedoch einen User_Alias ​​mit demselben Namen wie ein User_Alias ​​in der Hauptdatei /etc/sudoers. Jeder Versuch, sudo danach auszuführen, führte zu einem Analysefehler.

Meine Frage ist folgende: Wie teste ich Aktualisierungen meiner Sudoers-Dateien von Ansible aus, die solche Fehler abfangen können? Sobald die Datei vorhanden ist, kann der Fehler durch Ausführen von abgefangen werden visudo -c, aber dies als Validierungsschritt einzufügen, funktioniert nicht. Ansible erfordert den %sPlatzhalter, und selbst wenn dies nicht der Fall wäre, wird die Validierung durchgeführt, bevor die Datei an die richtige Stelle kopiert wird, sodass der Fehler dadurch visudo -cnicht abgefangen würde.

Antwort1

Haben Sie Folgendes versucht:

- copy:
    src: '{{ item }}'
    dest: '/etc/sudoers.d/{{ item }}'
    owner: root
    group: root
    mode: 0440
    validate: 'bash -c "cat /etc/sudoers %s | visudo -cf-"'

Für mich geht das.

Antwort2

Ich habe es zum Laufen gebracht. So habe ich es gemacht: Zuerst habe ich eine Reihe von Ansible-Aufgaben hinzugefügt, um ein Staging-Verzeichnis unter /etc/sudoers.stage.d zu erstellen und den Inhalt von /etc/sudoers.d dorthin zu kopieren. Dann lade ich die Dateien in diesen Staging-Bereich hoch und führe, falls eine davon geändert wird, ein benutzerdefiniertes Skript aus, um sie zu aktivieren.

So sieht die Logik im Playbook jetzt aus

- name: delete staging area
  file:
    path: "/etc/sudoers.stage.d"
    state: absent
  changed_when: false

- name: copy /etc/sudoers.d to staging area
  shell: "cp -rp /etc/sudoers.d /etc/sudoers.stage.d"
  changed_when: false

- name: stage sudoers files
  copy:
    src: "{{item}}"
    dest: "/etc/sudoers.stage.d/{{item}}"
    backup: yes
    owner: root
    group: root
    mode: 0440
    validate: /usr/sbin/visudo -cf %s
  with_items:
    - admins
    - apache
    - monitor
  register: sudoers_d

- block:
  - name: push out activate script
    copy:
      src: activate_sudoers.sh
      dest: /usr/local/bin/activate_sudoers.sh
      owner: root
      group: root
      mode: 0700

  - name: activate change
    shell: /bin/sh /usr/local/bin/activate_sudoers.sh /etc/sudoers.stage.d

  when: sudoers_d.changed

und so sieht das Skript activate_sudoers.sh aus.

#!/bin/sh

function usage {
    echo "Usage: $0 <stage directory>" >&2
    exit 1
}

function abort {
    echo "*** Error detected" >&2
    [ "$#" -gt 0 ] && echo "***" $@ >&2
    exit 1
}

PATH=/usr/bin:/bin:/usr/sbin:/sbin
export PATH

test $# -eq 1 || usage
test -d "$1" || abort "Stage directory $1: missing or not a directory"
test -d /etc/sudoers.old.d && rm -rf /etc/sudoers.old.d
test -d /etc/sudoers.old.d && abort "Failed to remove /etc/sudoers.old.d"

mv /etc/sudoers.d /etc/sudoers.old.d \
  && mv "$1" /etc/sudoers.d \
  && visudo -c

if [ $? -eq 0 ]; then
    # Success - clean up
    rm -rf /etc/sudoers.old.d
    exit 0
else
    # Failure - roll back
    rm -rf /etc/sudoers.d
    mv /etc/sudoers.old.d /etc/sudoers.d
    abort "sudoers update failed"
fi

Es ist etwas länger und komplexer als ich gehofft hatte, aber es erfüllt seinen Zweck. Hoffentlich ist es für jeden hilfreich, der auf das gleiche Problem stößt.

Antwort3

Machen Sie dasselbe nur mit Ansible-Modulen.

- name: Creating assemble directory
  file:
    path: /etc/sudoers.stage.d
    state: directory
    mode: 0600

- name: Applying sudoers.d files on assemble directory
  template:
    src: "{{ item }}.j2"
    dest: /etc/sudoers.stage.d/{{ item }}
    mode: 0400
  loop:
    - 10-wheel
    - 20-sys
  register: check

- name: Copying original sudoers to the assemble directory
  copy:
    remote_src: yes
    src: /etc/sudoers
    dest: /etc/sudoers.stage.d/99-sudoers
  when: check.changed

- name: Removing include line from 99-sudoers
  lineinfile:
    path: /etc/sudoers.stage.d/99-sudoers
    state: absent
    regex: ^#includedir /etc/sudoers.d
  when: check.changed

- name: Assembling unique config for validation
  assemble:
    src: /etc/sudoers.stage.d
    dest: /etc/sudoers.stage
    mode: 0600
    validate: visudo -cf %s
  when: check.changed

- name: Applying sudoers configurations
  template:
    src: "{{ item }}.j2"
    dest: /etc/sudoers.d/{{ item }}
    mode: 0440
  loop:
    - 10-wheel
    - 20-sys
  when: check.changed

verwandte Informationen