安全撤销旧密钥

AnsibleBeginner
立即练习

介绍

Ava 更换了工作室旧笔记本电脑。两台准备好的主机仍接受旧设备密钥,以及她当前和备用的密钥。只移除旧设备授权,同时保留账户与原始笔记。

这个独立单元以前一实验“为同事开通访问”中的用户、公钥、lookup 和循环练习为基础。它有自己的训练密钥和预建账户,不继承上一 VM 的文件或连接。

移除一把旧设备密钥

本步骤将在两台工作室主机撤销 Ava 的旧设备密钥,证明新连接被拒绝,并保留当前钥、备用钥和原有工作。

本单元有自己的全新环境。Ava 已在两台目标拥有账户和工作。每个账户当前接受三把训练密钥:当前、备用和旧设备。你只移除旧授权。删除密钥会阻止用它进行新的认证,不会终止已经认证的连接。本实验测试新连接,不宣称终止已有会话。

打开 Controller 并进入项目目录。若误切换目录,这条命令也可恢复:

cd /home/labex/project

阅读准备好的输入和客户端别名:

cat approved-staff.json
cat clients.conf

批准的课程账户是 studio_ava。待撤销密钥为 training-keys/ava-old.pub;training-keys/ava.pub 和 training-keys/ava-backup.pub 继续获准。以 .pub 结尾的是公钥,对应私钥保留在训练客户端。别名选择主机、用户和确切密钥。-F clients.conf 使用这份固定了信任的项目配置;每次 ssh 调用都建立新连接。保持清单、客户端设置、主机信任与训练密钥不变。

修改访问之前,先观察正常行为。单引号内,远端 shell 先运行 id,再运行 cat,二者以分号分隔:

ssh -F clients.conf web1-ava 'id -un; cat work/briefing.txt'
ssh -F clients.conf web2-ava 'id -un; cat work/briefing.txt'

两处身份都是 studio_ava,但 Riverside 与 Hill 笔记不同。也验证备用钥:

ssh -F clients.conf web1-ava-backup 'id -un'
ssh -F clients.conf web2-ava-backup 'id -un'

此时旧设备仍被接受:

ssh -F clients.conf web1-ava-old 'id -un'
ssh -F clients.conf web2-ava-old 'id -un'

仅从“待添加密钥列表”删除一把钥匙,并不等于请求移除它。用空添加列表安全观察这个差别。here-document 写入整个控制端文件:> 替换该文件,带引号的 YAML 防止 shell 展开。结束分隔符须单独位于一行开头。若 shell 因缺少结束分隔符仍在等待,按 Ctrl+C 取消未完成输入,再从正常提示符重跑完整块。[] 是空 YAML 列表,对它循环时没有可执行的条目。

cat > additions.yml <<'YAML'
- name: Add listed keys without removing other grants
  hosts: all
  become: true
  gather_facts: false
  vars:
    keys_to_add: []
  tasks:
    - name: Add a listed key
      ansible.posix.authorized_key:
        user: studio_ava
        key: "{{ lookup('file', item) }}"
        state: present
      loop: "{{ keys_to_add }}"
YAML
ansible-playbook additions.yml

两台主机均跳过密钥任务,未发生变更。该任务并没有检查所有可能授权并移除列表之外的密钥。旧设备仍能连接:

ssh -F clients.conf web1-ava-old 'id -un'

现在表达真正的撤销。group_vars/all.yml 把这份列表提供给两台清单主机,不会改动准备好的批准文件。每个对象指定课程用户和控制端公钥路径。若文件块有误,重跑即可替换那个控制端文件,不需要重置 VM。

cat > group_vars/all.yml <<'YAML'
revoked_keys:
  - name: studio_ava
    key_file: training-keys/ava-old.pub
YAML

使用已教过的密钥模块及 state: absent,只移除此钥,保留账户和其他授权。循环处理列出的每项撤销。双花括号解析当前条目,lookup 读取控制端公钥。collection 已为本项目离线安装。不要使用独占替换、删除主目录、锁定密码或修改平台 SSH 服务。

cat > revoke.yml <<'YAML'
- name: Revoke only the approved old device keys
  hosts: all
  become: true
  gather_facts: false
  tasks:
    - name: Remove each listed old public key
      ansible.posix.authorized_key:
        user: "{{ item.name }}"
        key: "{{ lookup('file', item.key_file) }}"
        state: absent
      loop: "{{ revoked_keys }}"
YAML

检查语法。若有 YAML 错误,读指定行,与完整块比较缩进和引号,只重写对应控制端文件。

ansible-playbook revoke.yml --syntax-check

这些账户已经存在,因此受支持的 check mode 可以预测移除密钥。--diff 会在输出显示公钥行,本次预览不需要这些内容。使用 --check:

ansible-playbook revoke.yml --check

两台主机都应预测有变更。check mode 尚未撤销真实授权。现在应用:

ansible-playbook revoke.yml

两台主机都须没有不可达或失败任务。接下来的两次连接预期失败,显示 Permission denied (publickey),退出状态为 255:

ssh -F clients.conf web1-ava-old 'id -un'
ssh -F clients.conf web2-ava-old 'id -un'

超时、连接被拒绝或主机密钥警告不能证明撤销。服务器必须仍可用,获准密钥必须仍有效。用当前钥和备用钥建立新连接,读取两个原始文件:

ssh -F clients.conf web1-ava 'id -un; cat work/briefing.txt'
ssh -F clients.conf web2-ava 'id -un; cat work/briefing.txt'
ssh -F clients.conf web1-ava-backup 'id -un; cat work/briefing.txt'
ssh -F clients.conf web2-ava-backup 'id -un; cat work/briefing.txt'

四次都须以 studio_ava 成功登录,显示对应原始笔记。保留文件字节、所有者和模式 0640;账户主目录/工作目录保持 0750,.ssh 保持 0700,authorized_keys 保持 0600。文件属于 studio_ava 及其主组。已有密钥模块会保留这些准备好的安全权限。

重复实际声明,再运行预测:

ansible-playbook revoke.yml
ansible-playbook revoke.yml --check

两行摘要均应为 changed=0、unreachable=0、failed=0。正确撤销是对实际授权的选择性修改,而非仅有成功摘要或空控制端列表。若选错密钥路径,先修正控制端数据;用之前教过的 state: present 恢复误删的合法钥,再重新应用正确的定向移除。不要通过清空整个密钥文件或将它设为所有人可写来恢复。

总结

你区分了省略添加与显式撤销,用 state absent 移除一项公钥授权,验证了真实的新连接拒绝,并保留当前/备用登录及两个原始工作文件。原样声明收敛,没有不必要的变更。