Ansible:维护sudoers列表的最佳实践

51
文档中,有一个使用lineinfile模块编辑/etc/sudoers的示例。
- lineinfile: "dest=/etc/sudoers state=present regexp='^%wheel' line='%wheel ALL=(ALL) NOPASSWD: ALL'"

感觉有点不专业。

我以为user模块中会有处理这个的选项,但似乎没有任何选项。

/etc/sudoers添加和删除用户的最佳实践是什么?


链接出现404错误,是否可以重新更新一下? - undefined
2个回答

82

那行代码实际上并没有将用户添加到sudoers,只是确保“wheel”组可以对所有命令进行无密码sudo。

至于将用户添加到/etc/sudoers中,最好的方法是将用户添加到必要的组中,然后给这些组相应的sudo访问权限。即使不使用Ansible也适用。

user module允许您指定一个排他的组列表,或仅将指定的组附加到用户已有的当前组中。这自然是幂等的,因为用户不能被定义为属于同一组多次。

示例剧本可能如下所示:

- hosts: all
  vars:
    sudoers:
      - user1
      - user2
      - user3
  tasks:
    - name: Make sure we have a 'wheel' group
      group:
        name: wheel
        state: present

    - name: Allow 'wheel' group to have passwordless sudo
      lineinfile:
        dest: /etc/sudoers
        state: present
        regexp: '^%wheel'
        line: '%wheel ALL=(ALL) NOPASSWD: ALL'
        validate: visudo -cf %s

    - name: Add sudoers users to wheel group
      user:
        name: "{{ item }}"
        groups: wheel
        append: yes
      with_items: "{{ sudoers }}"

30
lineinfile任务的属性中加入validate: visudo -cf %s将确保您不会弄错什么,因为它会先通过验证命令运行。该命令可以验证文件格式是否正确。 - xenithorb
请注意,validate 命令可能需要完整路径以便运行 visudo - Matt Hughes
这种方法的问题在于,你必须a)确保已经有wheel组并且已经在sudoers中启用,b)确保你想把用户放入wheel组而不是其他组。如果您想让用户成为NOPASSWD,但限制其命令怎么办?当您需要插入一行但在末尾时,lineinfile模块变得更加棘手。(因为将其插入到末尾会破坏#includedir语句,该语句必须在最后一行。) - Todd Walton
3
顺便提一下,如果你想知道 validate 中的 %s 是什么意思,它指的是应该被修改的文件的目标路径(dest)或路径。这里是文档 - AdamKalisz
很不错的答案。一个稍微不同的方法是使用copy模块来复制sudoers文件从控制节点到每个受控节点,而不是使用lineinfile模块。使用copylineinfile模块各有优缺点。我倾向于使用copy模块,以在控制节点上拥有单一的标准化文件,以确保每个受控节点都使用完全相同的文件。当然,使用copy也可能有缺点。这只是思考的食粮。 - JeremyCanfield

8

如果可能的话,我更倾向于使用/etc/sudoers.d/(这样做更安全、更模块化和自我描述性更强),因此这种方法看起来像:

$ cat files/*
%admins ALL=(ALL) NOPASSWD: ALL

$ cat tasks/*
- name: sudoers | Create sudoers.d files
  copy:
    src: ./
    dest: /etc/sudoers.d
    owner: root
    group: root
    mode: ug+rwX,o=
    force: yes

此处使用 visudo -cf 文件名 对文件进行预检查。


src: 中你缺少文件名。此外,force: yes 是多余的,因为这是默认设置。也许更明确地指定目标会更有意义,如果不存在的话,它将创建 /etc/sudoers.d 作为一个文件... - maxschlepzig
谢谢留言!实际上我正在考虑以下事项:文件名未丢失,语法意味着目录内所有内容;force 用于模块行动的特定强调,可以省略;如果 dest: 是不存在的路径,而 src: 是一个目录,则会创建 dest: 路径(目录,而不是文件)。 - dess
2
好的,“./”看起来像是一个疏忽。在您的文件目录中有一个子目录,比如说“src:sudoers.d”,可以说会使这个模式更加明显。 - maxschlepzig
个人而言,我更喜欢使用 ansible.builtin.template 而不是 ansiblt.builtin.copyansible.builtin.file。虽然我们可能不需要在文件中使用变量,但这样可以让我们在剧本结束时准确地报告是否有更改。 - Darren Felton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接