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 %s
Platzhalter, 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 -c
nicht 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