I would like to test if a user is able to SSH using SSH password. That's all I would like to do. I tried with modules: local_action, wait_for but those didn't get me the results. The playbook result must simply tell me where a connection succeeded or failed when trying to SSH.
The requirement is to test which user account succeeds in making a SSH connection to remote servers. The user who would be running the ansible script has multiple accounts on these servers but SSH login will succeed with just the right one which the user doesn't know. The user accounts all have the same password.
The inventory file:
all:
children:
FXO-Test:
hosts:
host1.abcd.com:
host2.abcd.com:
vars:
ansible_user: user1
The Playbook:
---
- hosts: "{{ targethosts }}"
gather_facts: no
tasks:
- name: Test connection
local_action: command ssh -q -o BatchMode=yes -o ConnectTimeout=3 {{ inventory_hostname }}
register: test_user
ignore_errors: true
changed_when: false
Invoked Using Command:
ansible-playbook checkLogin.yml -i ans_inventory_test --ask-pass --extra-vars "targethosts=FXO-Test" | tee verify_user.log
Expected to see which SSH connections failed and which ones worked.
Based on Vladimir Botka response, I tweaked the playbook a bit further to pull hostnames from an inventory file.
My Updated Playbook 'verifySSHLogin.yml':
- hosts: localhost
gather_facts: no
vars:
my_users:
- user1
- user2
my_hosts: "{{ query('inventory_hostnames', 'all') }}"
tasks:
- expect:
command: "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no {{ item.0 }}#{{ item.1 }}"
timeout: 2
responses:
(.*)password(.*):
- "password" # Fit the password
- "\x03" # Ctrl-C
(.*)\$(.*): "exit" # Fit the prompt
loop: "{{ my_users|product(my_hosts)|list }}"
register: result
ignore_errors: yes
- debug:
msg: "{{ (item.rc == 0)|ternary(item.invocation.module_args.command ~ ' [OK]',item.invocation.module_args.command ~ ' [KO]') }}"
loop: "{{ result.results }}"
Which I now invoke using below command:
ansible-playbook verifySSHLogin.yml -i ans_inventory_test --extra-vars "targethosts=FXO-Test" | tee verify_user.log
I can then do a grep against verify_user.log like this:
grep '\"msg\": \"ssh' verify_user.log
Which gives me below result which is what I was expecting:
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user1#host1.abc.corp.com [OK]"
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user1#host2.abc.corp.com [OK]"
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user1#host3.abc.corp.com [KO]"
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user2#host1.abc.corp.com [KO]"
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user2#host2.abc.corp.com [KO]"
"msg": "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no user2#host3.abc.corp.com [KO]"
Tweaked the playbook further to avoid hard-coding of SSH password. The final playbook looks like now:
- hosts: localhost
gather_facts: no
vars:
my_users:
- user1
- user2
my_hosts: "{{ query('inventory_hostnames', 'all') }}"
tasks:
- expect:
command: "ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no {{ item.0 }}#{{ item.1 }}"
timeout: 2
responses:
(.*)password(.*):
- "{{ ansible_password }}" # Fit the password
- "\x03" # Ctrl-C
(.*)\$(.*): "exit" # Fit the prompt
loop: "{{ my_users|product(my_hosts)|list }}"
register: result
ignore_errors: yes
- debug:
msg: "{{ (item.rc == 0)|ternary(item.invocation.module_args.command ~ ' [OK]',item.invocation.module_args.command ~ ' [KO]') }}"
loop: "{{ result.results }}"
The SSH password can be passed to ansible-playbook command like this:
ansible-playbook verifySSHLogin.yml -i ans_inventory_test -k --extra-vars "targethosts=FXO-Test" | tee verify_user.log
expect module shall do the job. Given the
user1#test_01 is able to log in, the play below
- hosts: localhost
vars:
my_users:
- user1
- user2
my_hosts:
- test_01
- test_02
tasks:
- expect:
command: "ssh {{ item.0 }}#{{ item.1 }}"
timeout: 2
responses:
(.*)password(.*):
- "password" # Fit the password
- "\x03" # Ctrl-C
(.*)\$(.*): "exit" # Fit the prompt
with_nested:
- "{{ my_users }}"
- "{{ my_hosts }}"
register: result
ignore_errors: yes
- debug:
msg: "{{ (item.rc == 0)|ternary(item.invocation.module_args.command ~ ' [OK]',
item.invocation.module_args.command ~ ' [KO]') }}"
loop: "{{ result.results }}"
gives (grep msg):
"msg": "ssh user1#test_01 [OK]"
"msg": "ssh user1#test_02 [KO]"
"msg": "ssh user2#test_01 [KO]"
"msg": "ssh user2#test_02 [KO]"
Related
I have the following scenario:
The inventory file is laid out as below:
[my_host]
host
server
[host:children]
hostm
hosts
[hostm]
host01
[hosts]
host02
host03
The group_vars file(s) is as below:
host.yml
user: user01
ansible_python_interpreter: /usr/bin/python3
The host_vars file(s) is as below:
host01.yml
id: ABC
nr: 00
host02.yml
id: DEF
nr: 20
host03.yml
id: GHI
nr: 02
Now using the above, I'm trying to run a playbook as described below:
custom.yml
- hosts: "{{ v_host | default([]) }}"
remote_user: root
tasks:
- name: Run the shell script
become: true
become_user: "{{ user }}"
become_method: su
become_exe: "su -"
ansible.builtin.shell: cleanipc {{ item.nr }} remove
with_items:
- "{{ v_host }}"
register: shell_result
no_log: false
changed_when: false
- name: print message
ansible.builtin.debug:
var: shell_result.stdout_lines
To run the playbook, I use the below command:
>ansible-playbook -i /path-to-inventory-file/file custom.yml -e 'v_host=host'
I'm trying to get the playbook to run the shell command on all child nodes of 'host', i.e., 'host01', 'host02' and 'host03', with the value of the variable 'nr' automatically substituted for each host.
I tried changing the lookup of the variable using hostvars as below:
ansible.builtin.shell: cleanipc {{ hostvars[item]['nr'] }} remove
But this didn't work either. Thank you for any help or guidance you can provide.
Thank you!
I want to ping several IPs with my linux server, namely:
ip 10.0.0.1 which is the host connected to the interface swp1
ip 10.0.0.2 which is the host connected to the interface swp2
with ip source 10.0.0.3 then the results are stored in a file. This command is executed through ansible with the following task:
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: VERIFICATION // CONNECTIVITY BY PING
shell: ping {{ item }} -c 2 -s 10.0.0.3 | grep -i received | awk '{print $4}'
register: ping
loop:
- 10.0.0.1
- 10.0.0.2
- copy:
content: "{{ ping.results | map(attribute='stdout') | join('\n') }}"
dest: ping.txt
and the contents of the ping.txt as follows:
2
0
This task was executed successfully, but, how do I add the connected interface of the pinged host, so that the ping.txt become:
swp1 : 2
swp2 : 0
What script can be added to get this result?
Does this help? I needed to remove the "-s 10.0.0.3" from mine but updated and commented out the link in the playbook below. My -s is not the same I would image as it is for your OS.
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: VERIFICATION // CONNECTIVITY BY PING
#shell: ping {{ item.ip }} -c 2 -s 10.0.0.3 | grep -i received | awk '{print "{{item.name}}:"$4}'
shell: ping {{ item.ip }} -c 2 | grep -i received | awk '{print "{{item.name}}:"$4}'
register: ping
loop:
- { ip: '10.0.0.1', name: 'swp1'}
- { ip: '10.0.0.2', name: 'swp2'}
- copy:
content: "{{ ping.results | map(attribute='stdout') | join('\n') }}"
dest: ping.txt
My ping.txt:
swp1:2
swp2:0
You can adjust the spacing within the "awk" command to get "swp1 : 2"
The interfaces of an node are accessible in the ansible_facts of the host.
Each interface has an entry with its name being a property of the ansible_facts dictionary and a list of all the existing interfaces can be accessed under ansible_facts.interfaces.
Also, the item used to create a result from a loop in a registered command can be accessed via the item property of the dictionaries under the results list.
So, you can create an intermediary fact in order to find back the name of the interface based on its IP before dumping the result to a file.
Here would be the resulting fact and copy tasks:
- set_fact:
ping_results: >-
{{
ping_results | default([]) + [
(
_interfaces_ip | zip(_interfaces_names)
| selectattr("0", "eq", item.item)
| first
).1
~ ' : '
~ item.stdout
]
}}
loop: "{{ ping.results }}"
loop_control:
label: "{{ item.item }}"
vars:
_interfaces: >-
{{
ansible_facts
| dict2items
| selectattr('key', 'in', ansible_facts.interfaces)
}}
_interfaces_names: >-
{{
_interfaces
| map(attribute="key")
}}
_interfaces_ip: >-
{{
_interfaces
| map(attribute="value.ipv4.address", default="n/a")
}}
- copy:
content: "{{ ping_results | join('\n') }}"
dest: ping.txt
Your modified playbook, should then, yield, in your case:
TASK [Gathering Facts] ***************************************************
ok: [localhost]
TASK [VERIFICATION // CONNECTIVITY BY PING] ******************************
ok: [localhost]
TASK [set_fact] **********************************************************
ok: [localhost] => (item=10.0.0.1)
ok: [localhost] => (item=10.0.0.2)
TASK [copy] **************************************************************
ok: [localhost]
And your ping.txt would contains:
swp1 : 2
swp2 : 0
Im using ansible 2.9.10 and have this playbook that runs powershell script on a vm vcenter.
the playbook works for some machines and some gets stuck forever without any error.
all vms are the same (same windows template)
---
- hosts: localhost
connection: local
vars:
vars_files:
- vars.yml
tasks:
- name: "load VPN"
vmware_vm_shell:
cluster: "{{ cluster }}"
datacenter: "{{ datacenter }}"
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
folder: "{{ folder }}"
vm_id: "{{ name }}"
vm_username: "{{ vm_username }}"
vm_password: "{{ vm_password }}"
vm_shell: 'C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe'
vm_shell_args: -ExecutionPolicy Bypass -File C:\SW\vpn.ps1
vm_shell_cwd: 'C:\MYDIR'
wait_for_process: yes
validate_certs: no
delegate_to: localhost
register: shell_command_output
- debug:
msg: "{{ shell_command_output }}"
If i run it manually i see it gets stuck here:
TASK [load VPN] **********************************************************************************************************************
task path: /root/ansible/api/base/vm-playbooks/install_vpn.yml:8
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912 `" && echo ansible-tmp-1615384930.8184772-37874402704912="` echo /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912 `" ) && sleep 0'
Using module file /usr/local/lib/python3.6/dist-packages/ansible/modules/cloud/vmware/vmware_vm_shell.py
<localhost> PUT /tmp/.ansible/tmp/ansible-local-103875urmwcpf8/tmpsckzefh6 TO /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912/AnsiballZ_vmware_vm_shell.py
<localhost> EXEC /bin/sh -c 'chmod u+x /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912/ /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912/AnsiballZ_vmware_vm_shell.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/env python3 /tmp/.ansible/tmp/ansible-tmp-1615384930.8184772-37874402704912/AnsiballZ_vmware_vm_shell.py && sleep 0'
How can I solve this ?
I want to create a user and set a password for him.
First password line and second one in user module doesnt work. Tried to pass it via hash variable, but no luck :)
If I run
and place value into the password line - it works just fine, still i'd like to use my password variable. Can you kindly show the way how i can send its value into this command?
"password | password_hash('sha512', 'mysecretsalt') }}"
.
---
- name: create ssh keys and distribute ssh public key for user
hosts: clients
become: yes
vars:
uname : Jim
create_user : False
password : imuser
tasks:
- name: creating password
set_fact:
hash : "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}"
- debug:
msg : "hashed password is {{ hash }}"
- name: create user if necessary
user:
name: "{{ uname }}"
state: present
password : "password | password_hash('sha512', 'mysecretsalt') }}"
# password : "{{ hash }}"
# password: $6$mysecretsalt$ZfUPIwkf1o9u8P04aJuQCgMfSZoIAeCoZpkbNKKn7LtiI.nQl8UWRIhO.rStaZzM8u0Bja3/9bzgOjagM5whY.
shell : /bin/bash
when: create_user == "True"
- name: get etc/passwd
shell: cat /etc/passwd
register: passwd
- block:
- debug:
var: passwd.stdout
- debug:
var: uname
when: inventory_hostname == "ansible_client1"
- name: create ssh key for user
user:
name: "{{ uname }}"
generate_ssh_key : yes
ssh_key_file : '{{ uname }}_id_rsa'
when: '"uname" in passwd.stdout'
register: create_key
- debug:
var: create_key
And the second question is:
Somehow task "create ssh key for user" is being skipped on ansible_client1 each run after i have deleted the user with userdel and his homedir with rm -rf since it looked weird at first runs of playbook. It works perfectly on 2nd host.
If i check /etc/passwd - user exist for both servers:
[admin#ansible_client1 ~]$ cat /etc/passwd | grep Jim
Jim:x:1004:1005::/home/Jim:/bin/bash
[admin#ansible_client2 Jim]$ cat /etc/passwd | grep Jim
Jim:x:1007:1008::/home/Jim:/bin/bash
User is being created each time on ansible_client1 and homedir is there, still task is being skipped and it looks like uname cannot be found in passwd.stdout somehow.
So... what's might be going on here i wonder
in the second task you have "password | password_hash('sha512', 'mysecretsalt') }}" it must be "{{ password | password_hash('sha512', 'mysecretsalt') }}" to use use te var password or "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}" to use the word password as password.
I am trying to shutdown databases in a loop, the catch is some databases run as a different user and others just run as oracle. I login as oracle user and run the playbook and if the database is run as oracle user it goes through fine. If it is running as a different user I would like to become that user (oracle user has permissions to do that).
Here is my main playbook:
[oracle#ansctrlsrv.localdomain epd3]$ cat test.yml
---
- hosts: testdrive
tasks:
- set_fact:
db_list: "{{ lookup('file', 'vars/' ~ inventory_hostname ~ '.dblist')|from_yaml }}"
- name: Shutdown running databases
include_tasks: shutdowndb.yml
loop: "{{ db_list }}"
DB list is as follows:
[oracle#ansctrlsrv.localdomain epd3]$ cat vars/dbsrv.localdomain.dblist
- ebs1
- ebs2
- ndb1
[oracle#ansctrlsrv.localdomain epd3]$ cat shutdowndb.yml
---
- debug: msg='Shutting down {{ item }}'
- name: Execute shutdown
shell: id "{{ item }}"
register: shutdown_output
become: "{{ item is search('ebs') | ternary('yes','no') }}"
become_user: "{{ item }}"
- debug: msg="{{ shutdown_output.stdout }}"
[oracle#ansctrlsrv.localdomain epd3]$ cat inventory
[testdrive]
dbsrv.localdomain
[oracle#ansctrlsrv.localdomain epd3]$ ansible-playbook -i inventory test.yml
TASK [Execute shutdown] ***
fatal: [dbsrv1.localdomain]: FAILED! => {"changed": false, "module_stderr": "Shared connection to dbsrv1.localdomain closed.\r\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1} ...ignoring
I tried this question on another thread but got closed, so trying another hand after realizing a few issues myself such as being unable to run blocks of code with a loop, etc.
Appreciate any help.
Set become user conditionally
Fix the line
shell: id "{{ item }}"
correct syntax (use shell only when necessary)
command: "id {{ item }}"
The playbook below
- hosts: testdrive
tasks:
- set_fact:
db_list: "{{ lookup('file', 'vars/' ~ inventory_hostname ~ '.dblist')|from_yaml }}"
- name: Shutdown running databases
include_tasks: shutdowndb.yml
loop: "{{ db_list }}"
with the included tasks
$ cat shutdowndb.yml
- debug:
msg:
- "shell: {{ 'shutdown.sh ' ~ item }}"
- "become: {{ item is search('ebs')|ternary('yes', 'no') }}"
- "become_user: {{ item }}"
give
"msg": [
"shell: shutdown.sh ebs1",
"become: yes",
"become_user: ebs1"
]
"msg": [
"shell: shutdown.sh ebs2",
"become: yes",
"become_user: ebs2"
]
"msg": [
"shell: shutdown.sh ndb1",
"become: no",
"become_user: ndb1"
]
Q: "Why the command whoami is still giving oracle rather than ebs1?"
A: Short answer: Because become is not set to True.
Debugging
1) Is it possible to become all of the users in db_list? Yes.
- hosts: test_01
become: no
remote_user: admin
vars:
db_list: ['ebs1', 'ebs2', 'ndb1']
tasks:
- command: whoami
become_user: "{{ item }}"
become: true
register: result
loop: "{{ db_list }}"
- debug:
msg: "{{ result.results|json_query('[].stdout') }}"
give
"msg": [
"ebs1",
"ebs2",
"ndb1"
]
2) Does search and ternary work properly? Yes.
- debug:
msg: "{{ item is search('ebs')|ternary(true, false) }}"
loop: "{{ db_list }}"
gives
"msg": true
"msg": true
"msg": false
3) Does become and become_user work properly?. Yes.
- command: whoami
become_user: "{{ item }}"
become: "{{ item is search('ebs')|ternary(true, false) }}"
register: result
loop: "{{ db_list }}"
- debug:
msg: "{{ result.results|json_query('[].stdout') }}"
give
"msg": [
"ebs1",
"ebs2",
"admin"
]