Ansible - 为多个用户管理多个SSH密钥&角色

时间:2016-11-08 09:30:43

标签: ssh ansible ssh-keys ansible-2.x

问题

我正在使用Ansible管理许多不同的服务器。每个服务器都有多个Linux用户,例如readonlyadmin等。

我的Ansible项目中还有一些文件,其中包含特定人群的所有SSH密钥 - 例如。 AppDevelopersPublicKeysDbaPublicKeys

不同的人群在不同的服务器上具有不同的访问级别。例如。在WebServer上,AppDevelopers具有管理员访问权限,而DBA可能只具有读取权限。在数据库服务器上,反之亦然。

为了实现上述目标,我对不同类型的服务器有不同的Ansible角色(例如WebAppServerDatabaseServer等)。然后,这些角色会针对它们设置变量readonly_key_filesadmin_key_files,列出应具有只读和管理员访问权限的角色的相应密钥文件。

理想的解决方案是:

  1. 确保公钥是独一无二的 - 例如。如果从Ansible中的AppDeveloperPublicKeys文件中删除公钥,则服务器也会删除此密钥
  2. 仅在实际更改内容时上传/更改服务器上的文件
  3. 使用--diff选项运行Ansible时显示文件的准确差异
  4. 我正在使用Ansible 2.2.0.0

    到目前为止尝试的解决方案

    以下所有内容均不符合我的要求:

    authorized_key with_file

    - authorized_key: user=readonly exclusive=no key={{item}}
      with_file: {{readonly_key_files}}
    
    • 这不符合要求1,因为它循环遍历多个文件,因此exclusive必须设置为no

    authorized_key with fact

    根据https://github.com/ansible/ansible-modules-core/pull/4167/files

    解决方案
    - name: "Generate developer keys from multiple files"
      set_fact: dev_key_list="{{ lookup('file', item) }}"
      register: dev_keys
      with_items: '{{developer_key_files}}'
    
    - name: "Merge developer keys into single list"
      set_fact: dev_keys_string={{ dev_keys.results | map(attribute='ansible_facts.dev_key_list') | join('\n') }}
    
    - authorized_key: user=readonly exclusive=yes key={{dev_keys_string}}
    
    • 这符合要求1,但(至少对我来说)不符合要求2 - 似乎生成的密钥顺序不确定,因此多次运行Playbook会导致authorized_keys步骤变化均匀当没有从文件中添加/删除密钥时。它似乎也不符合要求3,因为当我使用--check --diff运行时,我无法确切地看到Ansible认为哪些行正在改变,它只是突出显示该文件将被更改。

    authorized_key with_template

    - authorized_key: user=readonly exclusive=no key={{item}}
      with_template: {{readonly_keys.j2}}
    

    readonly_keys.j2的样子:

    {% for key_file in readonly_key_files %}
    {%   include '/files/' ~ key_file %}
    {% endfor %}
    
    • 这符合要求1和2,但在要求3上再次失败。当我使用--check --diff运行时,它只显示是否将更改SSH文件,而不是确切地添加/删除哪些行我期待它。

    结论

    还有其他方法可以解决这个问题吗?似乎在Ansible中使用--diffauthorized_keys可能存在问题...我能想到的唯一其他方法是根本不使用authorized_keys,而是管理这个作为常规文件/模板,它应该向我显示准确的差异(以及满足要求1和2)。

2 个答案:

答案 0 :(得分:0)

我在未回答的问题列表中找到了这个问题并进行了一些研究。在问题发生后不久,看起来diff功能已经添加到authorized_keys模块中。该提交在2017年初合并,似乎已包含在2.3及更高版本中。看起来您的第三个选项现在可以正常工作,但如果没有您的密钥设置,我无法确定。

https://github.com/ansible/ansible/commit/b0b7a636d8930a2c7192ea83ff890e4313aaf4d9#diff-e50c31b8374987e7c9dd4795d7f2e89f

https://github.com/ansible/ansible/pull/19277

答案 1 :(得分:0)

我解决此问题的方法是将变量中的文件名数组传递给我的user-account角色。然后,角色将获取每个文件的内容,将它们一起添加到以换行符分隔的字符串中,然后最终将该值设置为新用户的ssh键。

剧本文件:

- hosts: aws-node1
  roles:
    - { role: user-account, username: 'developer1', ssh_public_keyfiles: ['peter-sshkey.pub', 'paul-sshkey.pub'] }

user-account的角色定义:

- name: add user
  user:
    name: "{{username}}"


- name: lookup ssh pubkeys from keyfiles and create ssh_pubkeys_list
  set_fact:
    ssh_pubkeys_list: "{{ lookup('file', item) }}"
  with_items:
    "{{ssh_public_keyfiles}}"
  register: ssh_pubkeys_results_list


- name: iterate over ssh_pubkeys_list and join into a string
  set_fact:
    ssh_pubkeys_string: "{{ ssh_pubkeys_results_list.results | map(attribute='ansible_facts.ssh_pubkeys_list') | list | join('\n') }}"


- name: update SSH authorized_keys for user {{ username }} with contents of ssh_pubkeys_string
  authorized_key:
    user: "{{ username }}"
    key: "{{ ssh_pubkeys_string }}"
    state: present
    exclusive: yes