Verificando arquivos sudoers.d com Ansible

Verificando arquivos sudoers.d com Ansible

Eu tenho um manual do Ansible que uso para gerenciar nossos arquivos sudoers em nosso ambiente. Gostamos de manter um arquivo sudoers mínimo em /etc/sudoers, então qualquer coisa que quisermos adicionar é colocada em arquivos separados em /etc/sudoers.d.

Meu manual do Ansible contém a seguinte tarefa para enviar esses arquivos:

- 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

A tarefa contém uma cláusula de validação para garantir que o arquivo seja válido antes de enviá-lo, e isso geralmente funcionou bem. No entanto, hoje me deparei com um problema em que uma atualização quebrou o sudo. O arquivo passou na etapa de validação, mas continha um User_Alias ​​com o mesmo nome de User_Alias ​​no arquivo /etc/sudoers principal. Qualquer tentativa de executar o sudo depois disso resultou em um erro de análise.

Minha pergunta é esta: como faço para testar atualizações em meus arquivos sudoers do Ansible que podem detectar erros como este? Depois que o arquivo estiver no lugar, o erro pode ser detectado executando visudo -c, mas colocá-lo como etapa de validação não funciona. O Ansible requer o %sespaço reservado e, mesmo que não o faça, a validação é feita antes de copiar o arquivo no lugar, para que visudo -cnão seja detectado.

Responder1

Você já tentou isso:

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

Funciona para mim.

Responder2

Eu fiz funcionar. Aqui está o que eu fiz. Primeiro, adicionei um conjunto de tarefas Ansible para criar um diretório temporário em /etc/sudoers.stage.d e copiei o conteúdo de /etc/sudoers.d para ele. Em seguida, carrego os arquivos para esta área de teste e, se algum deles for alterado, executo um script personalizado para ativá-los.

Esta é a aparência da lógica do manual agora

- 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

e aqui está a aparência do script activate_sudoers.sh.

#!/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

É um pouco mais longo e complexo do que eu esperava, mas dá conta do recado. Esperamos que isso seja útil para qualquer pessoa que esteja enfrentando o mesmo problema.

Responder3

Fazendo a mesma coisa apenas com módulos Ansible.

- 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

informação relacionada