OpenEuler 24.03 用 Ansible 一键完成 SSH 互信 —— 从踩坑到最终方案

用 Ansible 一键完成 SSH 互信 ------ 从踩坑到最终方案

适用读者 :需要在多台 Linux 服务器之间快速建立免密登录(SSH 互信)的运维 / 开发人员。
环境:控制节点 + 若干 CentOS 7/8、Rocky、Ubuntu 混合目标机;Ansible 2.9/2.10+。


1. 背景

在批量运维场景里,先手动逐台 ssh-copy-id 太低效。最理想的做法是 一条 Playbook 就把公钥下发到所有服务器 。乍一看只需一个 authorized_key 模块,但在真实环境会碰到:

  1. SELinux 依赖 :目标机启用 SELinux,却没安装 python{,3}-libselinux,导致模块 abort。

  2. 解释器发现 WarningPlatform linux ... discovered Python interpreter at /usr/bin/python3 ...

  3. 包名差异:CentOS 7 与 8+、Debian/Ubuntu 的 SELinux 绑定包名不同。

  4. 密钥缺失 :控制节点可能还没生成 id_rsa.pub

  5. 密码安全 :不想把 ansible_ssh_pass 写死在 Playbook。

本文记录一次"从红到全绿"的完整踩坑与修正过程。


2. 问题与排查

序号 现象 根因 解决思路
1 Aborting, target uses selinux but python bindings (libselinux-python) aren't installed! 目标机启用 SELinux,但缺少 Python 绑定库 先用 raw 命令安装正确的库,再跑正常模块
2 No package libselinux-python available CentOS 8+ / Rocky 没有该包,正确包名是 python3-libselinux 根据包管理器自动分支安装
3 bash: 行 X: 语法错误:未预期的文件结束符 raw 多行脚本缩进 / 换行被拼坏 用 YAML 折行字符串 >,每段结尾加 ;
4 Platform linux ... discovered Python interpreter ... 解释器自动探测,仅 Warning 可在 inventory 指定 ansible_python_interpreter=/usr/bin/python3;也可忽略
5 没有公钥导致 lookup('file', '~/.ssh/id_rsa.pub') 报错 控制节点无密钥 openssh_keypair 预生成,幂等且只运行一次
6 Playbook 定义了两个 vars: 前后覆盖,易混淆 合并为一个 vars

3. 关键技术点

3.1 用 raw 绕过 Ansible 模块依赖
  • 为什么yum/dnf/apt 模块自身也要 import selinux,装库前就会失败。

  • 做法raw 仅走 SSH,不依赖远端 Python 环境,先把依赖装好。

    raw: >
    if command -v dnf >/dev/null; then dnf -y install python3-libselinux;
    elif command -v yum >/dev/null; then yum -y install libselinux-python3 || yum -y install libselinux-python;
    elif command -v apt-get >/dev/null; then apt-get update -qq && apt-get install -y python3-selinux;
    fi

3.2 控制节点自动生成密钥
  • 只在 localhost 执行,且 run_once: true

  • openssh_keypair 幂等:已有密钥就跳过。

    • openssh_keypair:
      path: "{{ local_key_path }}"
      type: rsa
      size: 4096
      state: present
      when: not key_stat.stat.exists
      delegate_to: localhost
      run_once: true
3.3 交互输入密码 / 后续免密
  • Playbook 加 vars_prompt;首次执行带 -k

  • 公钥下发后,再运行无需输入密码。


4. 最终 Playbook(ssh_trust.yml)

复制代码
---
- name: 自动生成 SSH 密钥并配置免密登录
  hosts: all
  gather_facts: no

  vars_prompt:
    - name: ansible_ssh_pass
      prompt: "请输入目标主机 SSH 密码"
      private: yes

  vars:
    ansible_user: root
    local_key_path: "{{ lookup('env', 'HOME') + '/.ssh/id_rsa' }}"

  pre_tasks:
    - name: 检查控制节点是否已有公钥
      ansible.builtin.stat:
        path: "{{ local_key_path }}.pub"
      register: key_stat
      delegate_to: localhost
      run_once: true

    - name: 如果没有就生成密钥对(控制节点)
      ansible.builtin.openssh_keypair:
        path: "{{ local_key_path }}"
        type: rsa
        size: 4096
        state: present
      when: not key_stat.stat.exists
      delegate_to: localhost
      run_once: true

  tasks:
    - name: 安装 SELinux Python 依赖(raw)
      raw: >
        if command -v dnf >/dev/null; then dnf -y install python3-libselinux;
        elif command -v yum >/dev/null; then yum -y install libselinux-python3 || yum -y install libselinux-python;
        elif command -v apt-get >/dev/null; then apt-get update -qq && apt-get install -y python3-selinux;
        fi
      become: true

    - name: 确保远端 .ssh 目录存在
      ansible.builtin.file:
        path: "/root/.ssh"
        state: directory
        mode: '0700'
        owner: root
        group: root
      become: true

    - name: 部署公钥到目标主机
      ansible.posix.authorized_key:
        user: root
        state: present
        key: "{{ lookup('file', local_key_path + '.pub') }}"

5. 使用方法

复制代码
# hosts.ini 里列出所有目标 IP
ansible-playbook -i hosts.ini ssh_trust.yml -k
  • 首次:输入密码,下发公钥。

  • 再次运行 :已免密,无需 -k

  • 若想彻底消除解释器 Warning,在 inventory 加:

    复制代码
    ansible_python_interpreter=/usr/bin/python3

6. 收获与最佳实践

  1. SELinux 依赖先装再用 ,必要时用 raw

  2. 包名与发行版强相关,写脚本时用分支判断。

  3. 密钥生成与部署保持幂等run_once + authorized_key

  4. 敏感信息交互输入或用 Vault,避免明文密码。

  5. 读报错要抓关键字,一次定位核心问题。

至此,一份可跨发行版的"一键互信" Playbook 就完成了。希望本文能帮你少走弯路,快速把绿色 ok=... failed=0 留在终端。祝运维愉快!

相关推荐
维天说2 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zhang~Ling2 小时前
从 fopen 到 struct file:从零开始拆解 Linux 文件 I/O
linux·运维·服务器
DeeplyMind2 小时前
Linux 深入 per-VMA lock:Linux 缺页路径如何摆脱 mmap_lock
linux·per-vma lock
爱写代码的阿森2 小时前
鸿蒙三方库 | harmony-utils之PreferencesUtil首选项数据监听详解
服务器·华为·harmonyos·鸿蒙·huawei
爱写代码的森2 小时前
蒙三方库 | harmony-utils之FileUtil文件重命名与属性查询详解
linux·运维·服务器·华为·harmonyos·鸿蒙·huawei
中微极客3 小时前
2026主流AI Agent框架技术选型与性能对比
运维·网络·人工智能
吠品3 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
XMAIPC_Robot3 小时前
软硬协同实时控制|RK3588业务调度+FPGA硬件时序,ethercat实现半导体设备微秒级响应(125us)
linux·arm开发·人工智能·fpga开发
AOwhisky4 小时前
Python 学习笔记(第十五期)——运维自动化(下·后篇):堡垒机实战——paramiko高阶篇
运维·python·学习·云原生·自动化·运维开发
重生的黑客4 小时前
Linux 进程优先级、切换与调度:从孤儿进程到 O(1) 调度模型
linux·运维·服务器·进程优先级·nice