You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ansible为多用户批量管理并移除指定authorized_keys

多用户SSH公钥的Ansible自动化管理问题

我是Ansible新手,目前需要实现:当存储多用户SSH公钥的YAML配置文件中移除某个用户的公钥时,自动从服务器对应用户的authorized_keys文件中删除该公钥。

现有YAML公钥配置文件内容

client:
 - key: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q==
  name: user1
 - key: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFiefwwefew4w223e3e==
  name: user1
 - key: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIku3hrbfwejw4ur4hfjewf4wkjr3434==  
  name: user2
 - key: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01Qrao3rj32hirbk2jewf239r232e3==
  name: user2

尝试过的方法及问题

方法1:使用authorized_key的exclusive参数循环

尝试循环处理每个密钥,但exclusive=True会导致每次循环都清空用户的authorized_keys只保留当前循环的密钥,最终用户只会剩下最后一个循环的密钥,无法保留该用户的所有有效密钥:

- name: Set authorized key for user
  become: yes
  authorized_key:
    user: "{{ item.name }}"
    state: present
    key: "{{ item.key }}"
    exclusive: True
  with_items:
    - "{{ client }}"

方法2:拼接所有密钥后批量设置

将所有用户的密钥拼接成字符串后为每个用户设置,导致所有用户的authorized_keys都包含所有密钥,完全混乱,无法实现用户独立管理:

- name: lookup ssh pubkeys from keyfiles and create ssh_pubkeys_list
  set_fact:
    ssh_keys: "{{ item.key }}"
  register: ssh_pubkeys_results_list
  with_items:
    - "{{ client }}"

- 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_keys') | join('\n')}}"

- name: lookup ssh pubkeys from name and create ssh_pubkeys_list
  set_fact:
    ssh_keys: "{{ item.name }}"
  register: ssh_pubkeys_results
  with_items:
    - "{{ client }}"

- name: Set authorized key for user
  become: yes
  authorized_key:
    user: "{{ item.name }}"
    state: present
    key: "{{ ssh_pubkeys_string }}"
    exclusive: True
  with_items:
    - "{{ client }}"

解决方案

核心思路是先按用户分组公钥,然后为每个用户单独处理其所有密钥,确保authorized_keys只保留该用户在YAML中的密钥,自动移除不在列表中的密钥:

- name: Group public keys by username
  set_fact:
    user_keys: "{{ client | groupby('name') }}"

- name: Configure authorized keys for each user
  become: yes
  authorized_key:
    user: "{{ item.0 }}"
    state: present
    key: "{{ item.1 | map(attribute='key') | join('\n') }}"
    exclusive: True
  loop: "{{ user_keys }}"

代码解释

  1. 分组公钥:使用groupby('name')过滤器将原始client列表按用户名分组,得到类似[('user1', [key_obj1, key_obj2]), ('user2', [key_obj3, key_obj4])]的结构。
  2. 循环处理每个用户:遍历分组后的结果,对每个用户:
    • item.0是用户名
    • item.1是该用户的所有密钥对象,通过map(attribute='key')提取所有密钥内容,再用join('\n')拼接成多行字符串
    • 设置exclusive=True,确保服务器上该用户的authorized_keys仅保留YAML中配置的这些密钥,自动删除不在列表中的密钥

这样就能实现:当YAML中移除某个用户的某条公钥时,服务器上该用户的authorized_keys会自动删除对应的密钥;新增密钥时也会自动添加,且每个用户的密钥独立管理。

内容的提问来源于stack exchange,提问作者WhizzY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:46:15