Edit current user's shell with ansible - linux

I'm trying yo push my dot files and some personal configuration files to a server (I'm not root or sudoer). Ansible connects as my user in order to edit files in my home folder.
I'd like to set my default shell to usr/bin/fish.
I am not allowed to edit /etc/passwd so
user:
name: shaka
shell: /usr/bin/fish
won't run.
I also checked the chsh command but the executable prompt for my password.
How could I change my shell on such machines ? (Debian 8, Ubuntu 16, Opensuse)

I know this is old, but I wanted to post this in case anyone else comes back here looking for advise like I did:
If you're running local playbooks, you might not be specifying the user and expecting to change the shell of user you're running the playbook as.
The problem is that you can't change the shell without elevating the privileges (become: yes), but when you do - you're running things as root. Which just changes the shell of the root user. You can double check that this is the case by looking at /etc/passwd and seeing what the root shell is.
Here's my recipe for changing the shell of the user running the playbook:
- name: set up zsh for user
hosts: localhost
become: no
vars:
the_user: "{{ ansible_user_id }}"
tasks:
- name: change user shell to zsh
become: yes
user:
name: "{{ the_user }}"
shell: /bin/zsh
This will set the variable the_user to the current running user, but will change the shell of that user using root.

I ended up using two ansible modules :
ansible expect
ansible prompt
First I record my password with a prompt :
vars_prompt:
- name: "my_password"
prompt: "Enter password"
private: yes
And then I use the module expect to send the password to the chsh command :
tasks:
- name: Case insensitve password string match
expect:
command: "chsh -s /usr/bin/fish"
responses:
(?i)password: "{{ my_password }}"
creates: ".shell_is_fish"
The creates sets a lock file avoiding this task to be triggered again. This may be dangerous because the shell could be changed after and ansible will not update it (because of the lock still present). You may want to avoid this behaviour.

Here is how I do it:
- name: Set login shell of user {{ ansible_env.USER }} to `/bin/zsh` with `usermod`
ansible.builtin.command: usermod --shell /bin/zsh {{ ansible_env.USER }}
become: true
changed_when: false

Ubuntu 16
add first line in ~/.bashrc
/usr/bin/fish && exit

Related

Ansible Run Command As Another User

I know my question is what become is designed to solve. And I do use it. However, my command seems to still be run as the ssh user. I'm trying to execute a which psql command to get the executable path. Running which psql as ssh user gives a different output than running the same command as my become user which is the output I want.
EDIT The problem is the $PATH variable ansible is using as suggested in comments. It is not using the correct $PATH variable. How can I direct ansible to use postgres users $PATH variable? Using environment module didn't work for me as suggested here https://serverfault.com/questions/734560/ansible-become-user-not-picking-up-path-correctly
EDIT2 So a solution is to use the environment module and set the path to the path I know has the psql executable but this seems hacky. Ideally, I'd like to just be able to use the become users path and not have to explicitly set it. Here's the hacky solution:
- name: Check if new or existing host
command: which psql
environment:
PATH: "/usr/pgsql-13/bin/:{{ansible_env.PATH}}"
become: yes
become_user: postgres
Playbook
---
- name: Playbook Control
hosts: all
become: yes
become_user: postgres
tasks:
- name: Check if new or existing host
shell: whoami && which psql
register: output
Relevant Output (the same as if I were to run the task command as my_user on myhost.net)
"stdout_lines": [
"postgres",
"/usr/bin/psql"
]
Expected Output (the output if I were to run the task command as postgres user on myhost.net)
"stdout_lines": [
"postgres",
"/usr/pgsql-13/bin/psql"
]
Inventory
myhost.net
[all:vars]
ansible_connection=ssh
ansible_user=my_user
Command
ansible-playbook --ask-vault-pass -vvv -i temp_hosts playbook.yml
In vault I only have the ssh pass of my_user.
Running the playbook with -vvv flag shows me that escalation was successful and that the output of this task is the output of running the command as ssh user, not become user. Any ideas?
Ansible by default uses sudo as the default become method.
Depending on how your linux system is configured (check /etc/sudoers), it could be that your $PATH variable is preserved for sudo commands.
You can either change this, or force ansible to use a different become method such as su:
https://docs.ansible.com/ansible/latest/user_guide/become.html#become-directives

Privilege escalation in Ansible is expecting a password

I am trying to create a file on a few remote nodes using Ansible.
I am connecting as 'xyz' user and after privilage escalation I want to become 'abc' user.
Problem here is Ansible is expecting a password to become 'abc' user, but i can directly use command : sudo su abc to switch as abc user on Putty.
My playbook runs fine if I pass the command like : ansible-playbook TestPlay.yml --ask-become-pass and then I enter the password.
But, we cannot share password for 'abc' user, so we need Ansible to directly become 'abc' user using sudo, which is not happening.
when I used : become_method: sudo in my playbook, it failed with {"msg": "Timeout (12s) waiting for privilege escalation prompt: "}.
I tried adding ANSIBLE_BECOME_EXE=’sudo su -‘ in hosts file and still it did not work!!.
Please let me know if i am missing something in my configuration.
My TestPlay playbook :
- name: TestPlay sample
become: true
become_method: su
become_user: abc
hosts: group1
tasks:
- name : create a file after becoming abc user
file:
path: /var/tmp/temp.txt
state: touch
mode: '0665'
Hosts file entry :
[group1]
ip address1
ip address2
[group1:vars]
ansible_user=xyz
ansible_password=passxyz

Error: sudo: a password is required\r\n - although user have permissions on sudoers

I am trying to run a simple Ansible playbook that shows a content of 'home' directory.
It runs successfully, but when I use:
become_user: "{{ TARGET_USER }}"
I get error:
"sudo: a password is required\r\n"
The 'Ansible user' is "blnapp1" and the 'Target user' is "couchbase"
I added permissions for "blnapp1" and "couchbase" users inside sudoers file as follows:
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
blnapp1 ALL=(ALL) NOPASSWD: ALL
blnapp1 ALL=(ALL) ALL
ansible ALL= NOPASSWD: /home/blnapp1/playbook #path to playbook
couchbase ALL=(ALL) NOPASSWD: ALL
couchbase ALL=(ALL) ALL
I also added to all of the users ssh public key of each other into /.ssh/authorized_keys
Here is my inventory file:
web1 ansible_host=**** ansible_connection=local
[couchbase-install:children]
couchbase_cluster_nodes
couchbase_server_nodes
[couchbase_cluster_nodes]
primary1 ansible_host=**** ansible_user=blnapp1 TARGET_USER=couchbase couchbase_primary_cluster_node=**** couchbase_cluster_admin_port=*** couchbase_bucket_name=exampleBucket group_server=default
[couchbase_server_nodes]
[all:vars]
#configuration_mode can be vars or cc
configuration_mode=vars
couchbase_data_path="/userdata/data/CB/var/lib/couchbase/data"
couchbase_index_path= "/userdata/data/CB/var/lib/couchbase/data"
yum_path="sudo /bin/yum"
#couchbase_admin="Administrator"
#couchbase_password="Administrator"
And here is my playbook:
---
- name: I-test
hosts: primary1
become: true
become_user: "{{ TARGET_USER }}"
tasks:
- debug:
msg: 'TARGET_USER is: "{{ TARGET_USER }}"'
- name: show repo content
shell:
cmd: ls -la /home
The only way I found is to add "blnapp1" user to 'wheel' group. However, I really don't want "blnapp1" to have 'wheel' permissions..
Thanks in advance!
blnapp1 ALL=(ALL) NOPASSWD: ALL
blnapp1 ALL=(ALL) ALL
Those 2 lines basically tell the exact same thing: let blnapp1 launch any command as anyone. But the first one tells sudo not to ask for a password while the second one doesn't.
And after testing quickly against a debian:buster docker image, it appears only the last line encountered rules in this case, making sudo always ask for a password.
Simply remove the second line in your sudoers file. Note that you have the exact same problem for your couchbase user.

Ansible become_user useradd issue

When trying to add a user using Ansible, I set ansible_become_user in my inventory to an account on the server that is a sudoer, but adding a user still fails with this error:
usermod: cannot open /etc/passwd usermod: failed to unlock /etc/passwd
I tested on the server running the command like this from my normal ssh account:
sudo -u <sudo_user> useradd test
useradd: cannot open /etc/passwd
useradd: failed to unlock /etc/passwd
If I su to my sudo account and run sudo useradd test, it works just fine.
I can also get it to work from my base SSH account by running su <sudo_user> -c "sudo useradd test".
The variable to set on your playbook/task is become_user not ansible_become_user. ansible_become_user is used when you set the value for a specific host/group in your inventory. See the privilege escalation doc
Moreover, you also have to set become: true for the above option to have any effect.
A quick example (does not become anything with debug, just to put you on track)
---
- hosts: all
become: true
become_user: someone
tasks:
- name: dummy task with play's defaults
debug:
msg: I would run with play's become_user
- name: dummy task with overriden user
become_user: some_other
debug:
msg: I would run with the overriden become_user
You can try another option, that is execute it like other user, for example root, and try it again.
For do it, edit /etc/sysconfig/jenkins
Then search for:
JENKINS_USER="jenkins"
And change it for
JENKINS_USER="root"
This should resolve the issue.
Another way is to add jenkins to visudo

Change linux password with Ansible playbook script when connecting as a non-root user without sudo privileges

I am trying to change password for a non-root Linux user from Ansible playbook.
To do so I tried to follow this link
Following the instruction I can successfully change the password of a non-root user by typing the code below in the terminal.
$ echo -e "your_current_pass\nlinuxpassword\nlinuxpassword" | passwd
Changing password for testuser.
(current) UNIX password: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
After that I am trying to automate the code with an Ansible playbook like below,
---
- hosts: all
gather_facts: no
tasks:
- name: "Check if user exists"
register: user1_exists
raw: getent passwd {{ ansible_user }}
ignore_errors: true
- name: "Change {{ ansible_user }} password"
raw: echo -e "my_current_pass\nmy_new_pass\nmy_new_pass" | passwd
when: user1_exists|success
I am using the raw module of Ansible here as most of my machines don't have Python installed. I do not have superuser (sudo) permission either to use become: True in playbook.
Also using password based authentication here to run the Ansible playbook on target machine. Not ssh based authentication.
But while I am executing the playbook I am getting this error,
TASK [change user1 password] ***************************************************
fatal: [192.168.0.57]: FAILED! => {"changed": true, "failed": true, "rc": 10,
"stderr": "Shared connection to 192.168.0.57 closed.\r\n", "stdout": "Changing
password for testuser.\r\n(current) UNIX password: passwd: Authentication
token manipulation error\r\npasswd: password unchanged\r\n", "stdout_lines":
["Changing password for testuser.", "(current) UNIX password: passwd:
Authentication token manipulation error", "passwd: password unchanged"]}
Could anyone show me the mistakes I am making here?
Use the built-in user module instead of a shell command. This requires become: True in your playbook. Note that the password parameter of the user module requires an encrypted value. The password_hash jinja filter will help you there.
- name: change user's password
user:
name: foo
password: "{{ 'passwordsaresecret' | password_hash('sha512') }}"
Your playbook is almost correct. I had the same kind of requirement and I used your playbook. There was just one mistake in your playbook, you forgot to enclose your password variables in '{{}}' braces. So I changed your playbook like below and it worked for me.
hosts: all
gather_facts: no
tasks:
- name: "Check if user exists"
register: user1_exists
raw: getent passwd {{ ansible_user }}
ignore_errors: true
- name: "Change {{ ansible_user }} password"
raw: echo -e "{{ ansible_password }}\n{{newpwd}}\n{{newpwd}}" | passwd
when: user1_exists|success
I've hacked together the following to solve this.
The password's don't show in log or even verbose log '-vvvvv' and are not visible in history on remote systems:
---
- name: Change password when connecting as a non-root/non-sudoer user.
#
# Ansible's 'user' module can only change a password if it is ran as a root user or 'become' is used.
# For a non-root user, when you run 'passwd', it asks for current password before you can enter a new one.
# Workaround: Create a a temporary script that updates the password and run that script remoteley
# and use 'no_log' directive to prevent passwords being visible in any log.
# Tested that passwords not visible in verbose output '-vvvvv' and not in 'history' of remote computers.
# The temporary script is deleted remotley automatically by 'script' module.
# Note:
# New password must comply with your passwd security policy.
hosts: all
gather_facts: no
vars_prompt:
- name: "curr_pass"
prompt: Type in current password
private: yes
- name: "new_pass"
prompt: Type in new password
private: yes
confirm: yes
## If you need to *temporary* hard-code credentials, use below.
## Delete after use or use vault if you want long-term storage.
#vars:
#- curr_pass: MyOldPass
#- new_pass: MyNewPass123!!
tasks:
- name: Create a temporary local script which will change the users password
copy:
dest: updatePassNonRootDynamic.sh
content: echo -e '{{curr_pass}}\n{{new_pass}}\n{{new_pass}}' | passwd
delegate_to: localhost
no_log: True
run_once: true
- name: Change password via temporary script on all hosts
script: updatePassNonRootDynamic.sh
- name: Remove the temporary local script
file:
path: updatePassNonRootDynamic.sh
state: absent
delegate_to: localhost
run_once: true

Resources