SSH Key-based authentication setup in LINUX (or) UNIX based OS is one of the major platform services related task and most frequently executed task by Unix admins. Ansible, An IT Automation tool could automate this tedious task as well.
SSH Key based authentication is indispensable when it comes to automation. Even some of the Ansible related tasks like SCP and RSYNC(synchronize) requires SSH Key based authentication to be enabled before running the ansible playbook.
In this post, we are going to see
How to enable the SSH Key-based authentication setup between multiple servers (or) hosts using Ansible ad-hoc
commands and playbook
Or How to transfer SSH Keys using ansible playbook and ad-hoc commands.
The Objective
I have two Red Hat Enterprise Linux servers named mwiapp01
and mwiapp02
and I have to enable SSH key based (passwordless) authentication between them, in both directions.
Index
- The Plan ( What we are trying to achieve in this article)
- SSH Key creation and Exchange using Ansible AD HOC commands
- SSH Key Creation and Exchange using Ansible Playbook
- Using Shell Module
- Using the authorized_key module
- SSH Key Creation and Exchange between multiple hosts
The Plan
We are going to see how to achieve our objective (or) requirement using Ansible ad-hoc command and ansible playbook with and without SSH authorized_key module.
Now we will see how to do this with both Ansible ad-hoc commands and playbook.
Let us consider that I have already grouped these servers into a host group named "app" in ansible_hosts
inventory file
Ansible AD-HOC Commands - Ansible SSH Key
In this method, we are going to use the Ansible ad hoc commands to perform the ssh key exchange and to copy the ssh keys between hosts. to know more about ansible ad hoc command refer to this article
Step 1: Create SSH Private key using SSH-KEYGEN for the user weblogic
aksarav@middlewareinventory:~$ ansible app -m shell -a "ssh-keygen -q -b 2048 -t rsa -N '' -C 'creating SSH' -f ~/.ssh/id_rsa creates='~/.ssh/id_rsa'" -i ansible_hosts -b – become-user=weblogic mwiapp02 | SUCCESS | rc=0 >> mwiapp01 | SUCCESS | rc=0 >>
Step 2: Make sure the Private key file is created
aksarav@middlewareinventory:~$ ansible app -m shell -a "ls -lrt ~/.ssh/id_rsa" -i ansible_hosts -b – become-user=weblogic mwiapp02 | SUCCESS | rc=0 >> -rw----- – 1 weblogic weblogic 1679 Sep 10 17:25 /home/weblogic/.ssh/id_rsa mwiapp01 | SUCCESS | rc=0 >> -rw----- – 1 weblogic weblogic 1675 Sep 10 17:25 /home/weblogic/.ssh/id_rsa
Step 3: Fetch the Key Public Key from the servers to the ansible master
aksarav@middlewareinventory:~$ ansible app -m fetch -a "src='~/.ssh/id_rsa.pub' dest='buffer/{{inventory_hostname}}-id_rsa.pub' flat='yes'" -i ansible_hosts -b – become-user=weblogic mwiapp02 | SUCCESS => { "changed": true, "checksum": "e128efa0cf4008d6f0a8652da44249d016a1c4fb", "dest": "/Users/aksarav/VirtualBox VMs/vagrantVM/buffer/mwiapp02-id_rsa.pub", "md5sum": "92332ffb86a310f2f7fa55e9e18e1f65", "remote_checksum": "e128efa0cf4008d6f0a8652da44249d016a1c4fb", "remote_md5sum": null } mwiapp01 | SUCCESS => { "changed": true, "checksum": "8ccbec5b91fd027e0e3ba8ca6fe2fa5e6faec0e8", "dest": "/Users/aksarav/VirtualBox VMs/vagrantVM/buffer/mwiapp01-id_rsa.pub", "md5sum": "f46044276aba3e4e6d4e918192676b76", "remote_checksum": "8ccbec5b91fd027e0e3ba8ca6fe2fa5e6faec0e8", "remote_md5sum": null }
Step 4: Copy the public key files to their respective destination servers to update authorized_keys
. mwiapp01 server's public key mwiapp01-id_rsa.pub
would go to mwiapp02 server and vice versa
4a) Copy the mwiapp01
public key to mwiapp02
and update authorized key using ansible authorized_key module
aksarav@middlewareinventory:~$ ansible app -m authorized_key -a "user='weblogic' state='present' key='{{ lookup('file','buffer/mwiapp01-id_rsa.pub')}}'" – limit=mwiapp02 -i ansible_hosts -b – become-user=weblogic mwiapp02 | SUCCESS => { "changed": true, "comment": null, "exclusive": false, "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIRJwtqDW614wf9vKm51oTi3mNt4CkYXB7aLxhT1sEsZILUBYBLFqc78QB2eqelmbvgWN471CcR4XAYPxImB+ibZLhBuLqz49lPWpaVl+D55THVJFiCJ5MrXZBeSD73hRX0y1cR4kuPflaYLodz/sNOeScufomlhs+cQzwGpShSXqNtTJMl9KqqWnczBut6mdK5X/+ETruCTVigLrKfoAGDbpFHm2MNuVNud34HUffKcnqXz8ihbH1tmlW5jy+j6mMDsMNfIA7coP/bKoa2vVMX1sFpAQQCPhejLV26IYM5fYABVYrzxLtaiioylRyvSWl7NFTpgua+dtkbdV7aEWr creating SSH", "key_options": null, "keyfile": "/home/weblogic/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "unique": false, "user": "weblogic", "validate_certs": true }
4b) Copy the mwiapp02
's public key to mwiapp01
and update authorized key using ansible authorized_key module
aksarav@middlewareinventory:~$ ansible app -m authorized_key -a "user='weblogic' state='present' key='{{ lookup('file','buffer/mwiapp02-id_rsa.pub')}}'" – limit=mwiapp01 -i ansible_hosts -b – become-user=weblogic mwiapp01 | SUCCESS => { "changed": true, "comment": null, "exclusive": false, "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDh50TVgulXoAEcRz0rn8SEXgVVoLpaebqk+PvhpRO27JbGC6WMlwpDNxEOdXjEn9Qlotm7zF/JUAjXaxEiPS7P5QSQjSTRxBu6YrTEV8sPnJyiocp+ll+1U74r18R88jE03+JOdxDroKROz3qpfT/vqzTHi6hnMdWs0n8vE09+oWPorW9lqrdWQ0C+AZShIWoSc/9nrLVDXci4rxhbwgrzyJbPd77sbV5yDoDfFLTKf3z3NQ48Gku/7zTdTNxrHOz8wop5Iqy7fqfH7jWAxlT0mWdJ6Ac+++ARj+x/v59hNfwMswc3rI2fE4tPNXIKC9tcnwVG3teaV1h4XxpHyWEt creating SSH", "key_options": null, "keyfile": "/home/weblogic/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "unique": false, "user": "weblogic", "validate_certs": true }
Step 5: Validate the SSH Key-based authentication between each server as weblogic
user ( If everything we did is correct, we should be able to execute commands over SSH from one another.
5a) Invoke SSH login from mwiapp01
to mwiapp02
and execute uname -n command
aksarav@middlewareinventory:~$ ansible app -m shell -a "ssh mwiapp02 'uname -a'" -i ansible_hosts -b – become-user=weblogic – limit=mwiapp01 mwiapp01 | SUCCESS | rc=0 >> Linux mwiapp02 3.10.0-514.2.2.el7.x86_64 #1 SMP Wed Nov 16 13:15:13 EST 2016 x86_64 x86_64 x86_64 GNU/Linux
5b) Invoke SSH login from mwiapp02
to mwiapp01
and execute uname -n command
aksarav@middlewareinventory:~/VirtualBox VMs/vagrantVM$ ansible app -m shell -a "ssh mwiapp01 'uname -a'" -i ansible_hosts -b – become-user=weblogic – limit=mwiapp02 mwiapp02 | SUCCESS | rc=0 >> Linux mwiapp01 3.10.0-514.2.2.el7.x86_64 #1 SMP Wed Nov 16 13:15:13 EST 2016 x86_64 x86_64 x86_64 GNU/Linux
Ansible Playbook to Exchange keys between hosts
Type1: With Ansible Shell module and Typical Commands
In this method, We are not going to use any ansible in-built module and every step is done manually by executing the shell command. The Playbook contains the following tasks
- Create an SSH Private and Public Key using
ssh-keygen
command - Fetch generated key files from remote servers [mwiapp01,mwiapp02] to ansible master
- Copy the file from the master to remote destination servers
- Add the public to the mentioned user's
authorized_keys
file
--- - name: Exchange Keys between servers become: yes become_user: weblogic hosts: app tasks: - name: SSH KeyGen command shell: > ssh-keygen -q -b 2048 -t rsa -N "" -C "creating SSH" -f ~/.ssh/id_rsa creates="~/.ssh/id_rsa" - name: Fetch the keyfile from one server to another fetch: src: "~/.ssh/id_rsa.pub" dest: "buffer/{{ansible_hostname}}-id_rsa.pub" flat: yes - name: Copy the file from master to the destination copy: src: "buffer/{{item.dest}}-id_rsa.pub" dest: "/tmp/remote-id_rsa.pub" when: "{{ item.dest != ansible_hostname }}" with_items: - { dest: "{{groups['app'][1]}}"} - { dest: "{{groups['app'][0]}}"} - name: add the public key into Authorized_keys file to enable Key Auth shell: "cat /tmp/remote-id_rsa.pub >> ~/.ssh/authorized_keys" register: addtoauth
Type2: With Ansible authorized_key module
In this method, we are going to use the ansible built-in module named "authorized_key"
. The following playbook has three steps
- Create an SSH Private and Public Key using
ssh-keygen
command - Fetch generated key files from remote servers [mwiapp01,mwiapp02] to ansible master
- Use the authorized_key module to copy the file remote machine and add it to the mentioned user's
authorized_keys
file ( If you could notice, the authorized_key module is actually performing the step3 and step4 from the manual method )
--- - name: Exchange Keys between servers become: yes become_user: weblogic hosts: app tasks: - name: SSH KeyGen command tags: run shell: > ssh-keygen -q -b 2048 -t rsa -N "" -C "creating SSH" -f ~/.ssh/id_rsa creates="~/.ssh/id_rsa" - name: Fetch the keyfile from one server to another tags: run fetch: src: "~/.ssh/id_rsa.pub" dest: "buffer/{{ansible_hostname}}-id_rsa.pub" flat: yes - name: Copy the key add to authorized_keys using Ansible module tags: run authorized_key: user: weblogic state: present key: "{{ lookup('file','buffer/{{item.dest}}-id_rsa.pub')}}" when: "{{ item.dest != ansible_hostname }}" with_items: - { dest: "{{groups['app'][1]}}"} - { dest: "{{groups['app'][0]}}"}
Ansible SSH Key Exchange between multiple hosts
Though the previously given examples have talked about Creating and Exchanging the Keys between only two servers. With a Simple modification in the same playbook. you would be able to achieve Exchanging the SSH Keys across multiple servers (or) all the servers in the host group.
Here is the Playbook to exchange SSH key between multiple hosts.
---
- name: Exchange Keys between servers
hosts: multi
tasks:
- name: SSH KeyGen command
tags: run
shell: >
ssh-keygen -q -b 2048 -t rsa -N "" -C "creating SSH" -f ~/.ssh/id_rsa
creates="~/.ssh/id_rsa"
- name: Fetch the keyfile from the node to master
tags: run
fetch:
src: "~/.ssh/id_rsa.pub"
dest: "buffer/{{ansible_hostname}}-id_rsa.pub"
flat: yes
- name: Copy the key add to authorized_keys using Ansible module
tags: runcd
authorized_key:
user: vagrant
state: present
key: "{{ lookup('file','buffer/{{item}}-id_rsa.pub')}}"
when: "{{ item != ansible_hostname }}"
with_items:
- "{{ groups['multi'] }}"
What is the difference
we have changed the loop with_items to parse all the servers in the host group instead of two specific servers. These are the two modified lines from the previous example.
when: "{{ item != ansible_hostname }}"
with_items:
- "{{ groups['multi'] }}"
Playbook execution Output
We have saved the Type1 playbook in the name sshkey-exchange-t1.yaml
and executed it. and here is the output.
In the last task. you could see that we successfully initiated an SSH connection from one another and ran the uname -a
command
Hope it helps.
We recommend the following article in case if you are looking to exchange IP between multiple hosts in Ansible. adding an IP in /etc/hosts file of multiple hosts in Ansible.
ansible update /etc/hosts file with IP of all hosts across all hosts
For any questions (or) support. Please feel free to comment
Rate this article [ratings]
Cheers,
Sarav AK
Follow me on Linkedin My Profile Follow DevopsJunction onFacebook orTwitter For more practical videos and tutorials. Subscribe to our channel
Signup for Exclusive "Subscriber-only" Content