使用 Ansible 检查 sudoers.d 文件

vir*_*tex 5 linux sudo ansible

我有一个 Ansible playbook,用于在我们的环境中管理我们的 sudoers 文件。我们喜欢在 /etc/sudoers 中保留一个最小的 sudoers 文件,然后我们想要添加的任何内容都会放入 /etc/sudoers.d 下的单独文件中。

我的 Ansible playbook 包含以下推送这些文件的任务:

- 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
Run Code Online (Sandbox Code Playgroud)

该任务包含一个validate 子句,用于在提交文件之前确保文件有效,这通常运行良好。但是,今天我遇到了更新破坏 sudo 的问题。该文件通过了验证步骤,但包含一个与主 /etc/sudoers 文件中的 User_Alias 同名的 User_Alias。之后任何尝试运行 sudo 都会导致解析错误。

我的问题是 - 如何从 Ansible 测试我的 sudoers 文件的更新,以捕获这样的错误?一旦文件就位,就可以通过运行来捕获错误visudo -c,但将其放入验证步骤不起作用。Ansible 需要%s占位符,即使没有,也会在将文件复制到位之前完成验证,visudo -c以免捕获它。

SAM*_*SAM 8

你有没有试过这个:

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

这个对我有用。


vir*_*tex 2

我成功了。这就是我所做的。首先,我添加了一组 Ansible 任务,在 /etc/sudoers.stage.d 处创建一个暂存目录,并将 /etc/sudoers.d 的内容复制到其中。然后,我将文件上传到此暂存区域,如果其中任何文件发生更改,则运行自定义脚本来激活它们。

这就是剧本中的逻辑现在的样子

- 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
Run Code Online (Sandbox Code Playgroud)

这是 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
Run Code Online (Sandbox Code Playgroud)

它比我希望的要长一些,也更复杂一些,但它完成了工作。希望这对遇到同样问题的其他人有用。