Ansible实现Linux SSH免密码登陆的role模块,ansiblerole


  创建集群的时候,我们经常用到的一个通用模块就是 对多个主机指定的帐户,设置免密码登陆。

手动设置是网上常见的方法,但是对付2-3台马马虎虎,但是,系统部署经常要自动化,这样操作非常的痛苦。于是自己写了一个脚本,经过上百次的修改后,终于比较好用了。

 

github 源代码下载地址: https://github.com/HappyFreeAngel/passwordless-ssh-login.git

 

1.首先:

$ansible-galaxy init passwordless-ssh-login

创建基本目录结构

happy:tmp happy$ tree passwordless-ssh-login
passwordless-ssh-login
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

8 directories, 8 files
 

2. 把一下内容  main.yml  替换tasks/main.yml

#version:1.2.1 2018.08.07 22:57   2018.08.24  修改了user_ssh_dir 一经定义后面没有被修改的错误.
# tasks file for passwordless-ssh-login
# 参数传入演示   2个参数
#user_host_list=?
#username=? centos,
#password=? kaixin.com,
#auto_generate_etc_host_list=? False
#sudo_privilege? True 显示传入
    - set_fact: passwordless_ssh_login_deploy_start_timestamp="{{lookup('pipe','date \"+%Y-%m-%d %H:%M:%S\"')}}"

    - set_fact: max_wait_time_in_seconds=300
      when: max_wait_time_in_seconds is undefined

    - set_fact: username="root"
      when: username is undefined



#
# python -c 'import crypt; print crypt.crypt("yourpassword", "$1$SomeSalt$")'

    - set_fact: password="$1xreu3ze.m5A", #这里的密码形式必须是salt的加密形式
      when: password is undefined

    - set_fact: auto_generate_etc_host_list = False
      when: auto_generate_etc_host_list is undefined

    - set_fact: user_ssh_dir="/home/{{username}}/.ssh"
      when: username != 'root'
      
    - set_fact: user_ssh_dir="/root/.ssh"
      when: username == 'root'

    - name: add user {{ username }} on vm
      user:
        name: "{{username}}"
        password: "{{password}}"
        state: present
        append: yes
        generate_ssh_key: yes
        ssh_key_bits: 2048
        ssh_key_file: .ssh/id_rsa
      when: username != 'root'

    - stat: path=/root/.ssh/id_rsa
      register: temp_file_path
      ignore_errors: yes

    - name: "Create a 2048-bit SSH key for user root in /root/.ssh/id_rsa 如果尚未存在的话."
      user:
        name: root
        generate_ssh_key: yes
        ssh_key_bits: 2048
        ssh_key_file: .ssh/id_rsa
      when: username == 'root' and  temp_file_path.stat.exists == False

    #添加一个sudo user {{username}}
    - name: Make sure we have a 'wheel' group 当用户不是root时才创建
      group:
        name: wheel
        state: present
      when: username != 'root'

    - name: Allow 'wheel' group to have passwordless sudo
      lineinfile:
        dest: /etc/sudoers
        state: present
        regexp: '^%wheel'
        line: '%wheel ALL=(ALL) NOPASSWD: ALL'
      when: username != 'root'

    - set_fact: sudo_privilege = True
      when: sudo_privilege is undefined

    - name: "Add sudoers users to wheel group  for {{username}}"
      user: name={{username}} groups=wheel append=yes state=present createhome=yes
      when: sudo_privilege == True and username != 'root'

    - include_role:
        name: etc-hosts-with-hostlist
      vars:
        etc_host_list: "{{ user_host_list }}"
      when: auto_generate_etc_host_list == True

    #to do 每次运行目录都不一样,确保多个ansible playbook并行运行,目录不会冲突,运行期间所有hosts 共享这一目录.
    - set_fact: random_pub_key_file_path={{playbook_dir}}/tmp/remote_host_pub_key_store_{{ 200000000 | random }}_{{ 200000000 | random }}
      when: random_pub_key_file_path is not defined
      run_once: yes

    - name: "创建临时目录{{playbook_dir}}/tmp 如果不存在的话."
      file: path={{random_pub_key_file_path}}  state=directory mode=0766
      delegate_to: 127.0.0.1

     #注意 fetch  dest={{playbook_dir}}/tmp/id_rsa_{{item.name}}/ 后面的/不是可有可无的. 有/表示使用这个目录,没有/表示要把/abc.host/home/user/添加在后面.
    - name: "username={{username}}取回每个主机上的公匙 fetch id_rsa.pub 到 ansible running host"
      fetch: src={{user_ssh_dir}}/id_rsa.pub   dest={{random_pub_key_file_path}}/id_rsa_{{item.name}}/  flat=yes fail_on_missing=yes  #mode=766  group={{username}} owner={{username}} 这个本地机器上可能没有这个帐号.
      delegate_to: "{{ item.name }}"
      with_items:  "{{ user_host_list }}"
      ignore_errors: yes
      retries: 3
      when: inventory_hostname == user_host_list[0].name

    #如果这个主机名称不一样,怎么取? todo 当 phoenix_host_list: "{{hostdict['hadoop-namenode-hosts']}}+{{hostdict['hadoop-datanode-hosts']}}  运行的hosts不在host_list时会出错,为什么
    - name: "username={{username}}修改authorized_keys {{ inventory_hostname }},合并所有{{ user_host_list }}的id_rsa.pub 到ansible所在机器目录{{random_pub_key_file_path}}/authorized_keys"
      shell:  cat  {{random_pub_key_file_path}}/id_rsa_{{item.name}}/id_rsa.pub >> {{random_pub_key_file_path}}/authorized_keys
      delegate_to: 127.0.0.1  #localhost
      with_items:  "{{ user_host_list }}"
      run_once: yes
      #when: inventory_hostname == item.name  #??user_host_list[0]

    - name: "username={{username}}分发给每个机器 authorized_keys {{ inventory_hostname }}"
      copy: src={{random_pub_key_file_path}}/authorized_keys   dest={{user_ssh_dir}}/authorized_keys
      delegate_to: "{{ inventory_hostname }}"
      with_items:  "{{user_host_list}}"
      

    - name: "username={{username}}自动生成各个免密码登陆主机的域名  {{ inventory_hostname }}  {{user_ssh_dir}}/known_hosts on {{user_host_list[0].name}}"
      shell: ssh-keyscan {{ item.name }} >>{{user_ssh_dir}}/known_hosts; chown {{username}}:{{username}}  {{user_ssh_dir}}/known_hosts ; chmod 644 {{user_ssh_dir}}/known_hosts
      delegate_to: "{{ inventory_hostname }}"
      with_items:  "{{user_host_list}}"

    - name: username={{username}}自动生成各个免密码登陆主机的域名简称  {{ inventory_hostname }}  {{user_ssh_dir}}/known_hosts on "{{user_host_list[0].name}}"
      shell: ssh-keyscan {{ item.name.split('.')[0] }} >>{{user_ssh_dir}}/known_hosts; chown {{username}}:{{username}}  {{user_ssh_dir}}/known_hosts ; chmod 644 {{user_ssh_dir}}/known_hosts
      delegate_to: "{{ inventory_hostname }}"
      with_items:  "{{user_host_list}}"

    - name: username={{username}}自动生成各个免密码登陆主机的IP  {{ inventory_hostname }}  {{user_ssh_dir}}/known_hosts on "{{user_host_list[0].name}}"
      shell: ssh-keyscan {{ item.ip }} >>{{user_ssh_dir}}/known_hosts; chown {{username}}:{{username}}  {{user_ssh_dir}}/known_hosts ; chmod 644 {{user_ssh_dir}}/known_hosts
      delegate_to: "{{ inventory_hostname }}"
      with_items:  "{{user_host_list}}"

    - name: "username={{username}}清理垃圾, user_ssh_dir={{user_ssh_dir}}保护环境干净,确保不影响其他账号的运行."
      file: path={{random_pub_key_file_path}}/ state=absent
      delegate_to: 127.0.0.1  #localhost

    - set_fact: passwordless_ssh_login_deploy_stop_timestamp="{{lookup('pipe','date \"+%Y-%m-%d %H:%M:%S\"')}}"

    - name: "角色:passwordless_ssh_login安装执行共耗时{{( (passwordless_ssh_login_deploy_stop_timestamp | to_datetime) - (passwordless_ssh_login_deploy_start_timestamp | to_datetime)).total_seconds()}}秒."
      debug: msg=" "

 

 

 

具体使用方法:

先定义spark-hosts变量
spark-hosts:
  - name: "spark-node1.cityworks.cn"
  - name: "spark-node2.cityworks.cn"
  - name: "spark-node3.cityworks.cn"
  - name: "spark-node4.cityworks.cn"   
  - name: "spark-node5.cityworks.cn"

 




#创建多主机之间root免密码登陆
- name: "安装不同主机间用户之间root免密码登陆 passwordless-ssh-login 这个不是必须的,只是为了方便用户使用."
  include_role:
     name: passwordless-ssh-login
  vars:
    user_host_list: "{{spark_host_list}}"
    username: "root"
    password: "{{root_salt_password}}"
    sudo_privilege: True
    auto_generate_etc_host_list: False

#下面这个操作会创建{{spark_username}}帐号,下面的group, owner 等创建文件夹时会用到.
- name: "安装不同主机间用户{{spark_username}}之间免密码登陆 passwordless-ssh-login"
  include_role:
     name: passwordless-ssh-login
  vars:
    user_host_list: "{{spark_host_list}}"
    username: "{{spark_username}}"
    password: "{{spark_salt_password}}"
    sudo_privilege: True
    auto_generate_etc_host_list: True
  become_user: root

 

 

 

随便从spark-node1,spark-node2,spark-node3,spark-node4,spark-node5 用root 或spark 登陆到任意一台,包括本机 都可以实现使用相同帐户,免密码登陆了。

特别注意: 下面这种情况

 [root@spark-node4 ~]# ssh spark@spark-node3
spark@spark-node3's password:

是需要密码的。 也就是说:当前用户A和当前机器,如果要免密码登陆不同的帐户B和任意spark-node1 到spark-node5 这个role模块目前是不支持的。 因为我们讨论的实现是:同帐户在不同主机之间免密码登陆。

 

相关内容

    暂无相关文章