Using --become for ansible_connection=local - ansible

With a personal user account (userx) I run the ansible playbook on all my specified hosts. In ansible.cfg the remote user (which can become root) to be used is:
remote_user = ansible
For the remote hosts this all works fine. It connects as the user Ansible, and executes all tasks as wished for, also changing information (like /etc/ssh/sshd_config) which requires root rights.
But now I also want to execute the playbook on the Ansible host itself. I put the following in my inventory file:
localhost ansible_connection=local
which now indeed executes on localhost. But as userx, and this results in "Access denied" for some task it needs to do.
This is of course somewhat expected, since remote_user tells something about remote, not the local user. But still, I expected that the playbook would --become locally too, to execute the tasks as root (e.g. sudo su -). It seems no to do that.
Running the playbook with --become -vvv tells me
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: userx
and it seems not to try to execute the tasks with sudo. And without using sudo, the task fails.
How can I tell ansible to to use sudo / become on the local connection too?

Nothing special is required. Proof:
The playbook:
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- command: whoami
register: whoami
- debug:
var: whoami.stdout
The execution line:
ansible-playbook playbook.yml --become
The result:
PLAY [localhost] ***************************************************************************************************
TASK [command] *****************************************************************************************************
changed: [localhost]
TASK [debug] *******************************************************************************************************
ok: [localhost] => {
"changed": false,
"whoami.stdout": "root"
}
PLAY RECAP *********************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
The ESTABLISH LOCAL CONNECTION FOR USER: message will always show the current user, as it the account used "to connect".
Later the command(s) called from the module get(s) executed with elevated permissions.
Of course, you can add become: yes on either play level or for individual tasks.

Related

This command has to be run under the root user. But I am root only

I have a simple playbook that tries to install packages.
My task is failing(see output).
I can ping the host, and manually I can run the command as the super user(tco).
my ansible.cfg
[defaults]
inventory = /Users/<myuser>/<automation>/ansible/inventory
remote_user = tco
packages
packages:
- yum-utils
- sshpass
playbook
---
- hosts: all
vars_files:
- vars/packages.yml
tasks:
- name: testing connection
ping:
remote_user: tco
- name: Installing packages
yum:
name: "{{ packages }}"
state: present
Running playbook:
ansible-playbook my-playbook.yml --limit master --become --ask-become-pass --become-user=tco --become-method=sudo
Output:
ansible-playbook register_sys_rh.yml --limit master --become --ask-become-pass --become-user=tco --become-method=sudo
BECOME password:
PLAY [all] ******************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [xx.xxx.13.105]
TASK [testing connection] ***************************************************************************************************************************************************
ok: [xx.xxx.13.105]
TASK [Installing packages] **************************************************************************************************************************************************
fatal: [xx.xxx.13.105]: FAILED! => {"changed": false, "msg": "This command has to be run under the root user.", "results": []}
PLAY RECAP ******************************************************************************************************************************************************************
xx.xxx.13.105 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
inventory:
ansible-inventory --list | jq '.master'
{
"hosts": [
"xx.xxx.13.105"
]
}
I have copied my id_rsa.pub to the host already. I cannot loging to the host without a password.
I can log in and do sudo su or run any other command that needs root privilege.
[tco#control-plane-0 ~]$ whoami
tco
[tco#control-plane-0 ~]$ hostname -I
xx.xxx.13.105 192.168.122.1
[tco#control-plane-0 ~]$ sudo su
[sudo] password for tco:
[root#control-plane-0 tco]#
I explicitly override user, sudo_method through ansible_cli, no idea what I am doing wrong here.
Thanks in advance.
Fixed it.
But, I need to understand the Ansible concept better.
I changed ansible.cfg to this(changed become_user to root)
[defaults]
inventory = <my-inventory-path>
remote_user = tco
[privilege_escalation]
become=True
become_method=sudo
become_ask_pass=False
become_user=root
become_pass=<password>
And, running it like this:
ansible-playbook my-playbook.yml --limit master
this gives me an error:
FAILED! => {"msg": "Missing sudo password"}
So, I run like this:
ansible-playbook my-playbook.yml --limit master --ask-become-pass
and when a password is prompted I provide tco password not sure what is the password for the root user is.
And this works.
Not sure why cfg file password is not working, even though I provide the same password when prompted.
As per my understanding, when I say become_user and become_pass that is what ansible uses to run privilege commands. But, here I am saying remote_user: tco and become_user:root
This error is because the playbook is unable to run on the remote nodes as a root user.
We can modify the ansible.cfg file in order to resolve this issue.
Steps:
Open the ansible.cfg, default command is: sudo vim /etc/ansible/ansible.cfg
Search for regular expression: /privilege_escalation ( / is basically searching for the keyword that follows in VIM)
Press I (Insert mode), uncomment following lines:
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
Note: If the .cfg lines are not modified, the corresponding values can be passed via Terminal during the playbook execution(as specified in the question itself).
Run the playbook again with: ansible-playbook playbookname.yml
Note, if there is no ssh authentication pre-established between the Ansible controller and the nodes, appending -kK is required (this asks for the privileged user password for the remote nodes ) i.e. ansible-playbook playbookname.yml -kK
This will require you to input password for the SSH connection, as well as the BECOME password(the password for the privileged user on the node)

Why ansible doesn't do the task at first attempt in Gitlab?

I am executing some ansible playbooks via gitlab-ci and what I could see is
Ansible playbook executing successfully through pipeline, but it doesn't produce the output it is intended to do
When I retry the gitlab job, it produces the output I needed.
This is one of the many playbooks I am executing through gitlab:
1_ca.yaml
---
- hosts: 127.0.0.1
connection: local
tasks:
- name: Create ca-csr.json
become: true
copy:
dest: ca-csr.json
content: '{"CN":"Kubernetes","key":{"algo":"rsa","size":2048},"names":[{"C":"US","L":"Portland","O":"Kubernetes","OU":"CA","ST":"Oregon"}]}'
- name: Create ca-config.json
become: true
copy:
dest: ca-config.json
content: '{"signing":{"default":{"expiry":"8760h"},"profiles":{"kubernetes":{"usages":["signing","key encipherment","server auth","client auth"],"expiry":"8760h"}}}}'
- name: Create the ca.pem & ca-key.pem
# become: true
shell: |
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Basically what does this do is, it creates some certs I needed.
But in the first attempt even though pipeline passes and it doesn't generate these certs. When I restart (running the same job for the second time) that particular job in gitlab it generates these certs.
Why this is happening?
This is how my .gitlab-ci.yaml looks like:
Create-Certificates:
stage: ansible-play-books-create-certs
retry:
max: 2
when:
- always
script:
- echo "Executing ansible playbooks for generating certficates"
- ansible-playbook ./ansible-playbooks/1_ca/1_ca.yaml
- ansible-playbook ./ansible-playbooks/1_ca/2_admin.yaml
- ansible-playbook ./ansible-playbooks/1_ca/3_kubelet.yaml
- ansible-playbook ./ansible-playbooks/1_ca/4_kube-controller.yaml
- ansible-playbook ./ansible-playbooks/1_ca/5_kube-proxy.yaml
- ansible-playbook ./ansible-playbooks/1_ca/6_kube-scheduler.yaml
- ansible-playbook ./ansible-playbooks/1_ca/7_kube-api-server.yaml
- ansible-playbook ./ansible-playbooks/1_ca/8_service-account.yaml
- ansible-playbook ./ansible-playbooks/1_ca/9_distribute-client-server-cert.yaml
# when: delayed
# start_in: 1 minutes
tags:
- banuka-gcp-k8s-hard-way
PS: These ansible playbooks are executing in the ansible host itself, not in remote servers. So I can log into the ansible master server and check if these files are created or not.
running your playbook without the last shell module produces the follwing output:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [127.0.0.1] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [127.0.0.1]
TASK [Create ca-csr.json] *****************************************************************************************************************************************************************************************
[WARNING]: File './ca-csr.json' created with default permissions '600'. The previous default was '666'. Specify 'mode' to avoid this warning.
changed: [127.0.0.1]
TASK [Create ca-config.json] **************************************************************************************************************************************************************************************
[WARNING]: File './ca-config.json' created with default permissions '600'. The previous default was '666'. Specify 'mode' to avoid this warning.
changed: [127.0.0.1]
PLAY RECAP ********************************************************************************************************************************************************************************************************
127.0.0.1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
and checking the existence:
$ ls ca* -al
-rw------- 1 root root 155 Aug 17 02:48 ca-config.json
-rw------- 1 root root 129 Aug 17 02:48 ca-csr.json
so although it's quite dirty way of writing a playbook - it works.
Why is it dirty ? :
you're not using any inventory
you should use local_action and not connection: local for local tasks
you are misusing ansible that is multi-node configuration management to do a bash script task
so in conclusion - there's nothing wrong with your ansible playbook - or maybe the file permissions (?) and if it does not run - you should look more in the gitlab-ci direction.
you need to provide more details on Gitlab-CI setup but - maybe the stage is not correct ?

Ansible and "sudo su - "

I'm trying to create an ansible playbook that will work in my current work environment. I login to servers as user "myuser" using ssh keys. I was never given a password, so I don't know it. Most of the commands I run are executed as a different non-root user - e.g. "appadmin". I become these users via "sudo su - appadmin", since I don't have the passwords for this user either.
Different variations I've tried either complain "sudo: a password is required" or time out after 12 seconds. I'll show this second example.
The playbook is very simple:
---
- hosts: sudo-test
gather_facts: False
remote_user: myuser
become: yes
become_user: appadmin
tasks:
- name: who
shell: whoami > qwert.txt
My host entry is as follows:
[sudo-test]
appserver.example.com ansible_become_method=su ansible_become_exe="sudo su"
This is the error I get:
pablo#host=> ansible-playbook test_sudo.yml
PLAY [sudo-test] ****************************************************************************************************
TASK [who] **********************************************************************************************************
fatal: [appserver.example.com]: FAILED! => {"msg": "Timeout (12s) waiting for privilege escalation prompt: "}
to retry, use: --limit #/home/pablo/ansible_dir/test_sudo.retry
PLAY RECAP **********************************************************************************************************
appserver.example.com : ok=0 changed=0 unreachable=0 failed=1
At this point I agree that the playbook and inventory are configured correctly. I believe the issue is that /etc/sudoers doesn't permit my "appadmin" user to run in a way that allows me to leverage ansible's ability to become another user. This thread describes a similar scenario - and limitation.
The relevant section of /etc/sudoers looks like this:
User myuser may run the following commands on this host:
(root) NOPASSWD: /bin/su - appadmin
It seems I would have to have the sysadmin change this to:
User myuser may run the following commands on this host:
(root) NOPASSWD: /bin/su - appadmin *
Does this sound right?
i dont find any issue with yaml, infact i got it tested in my ansible2.8 environment.
---
- hosts: node1
gather_facts: False
remote_user: ansible
become: yes
become_user: testuser
tasks:
- name: who
shell: whoami
register: output
- debug: var=output
and inventory:
[node1]
node1.example.com ansible_become_method=su ansible_become_exe="sudo su"
output:
TASK [debug] ****************************************************************************************************************************
ok: [node1.example.com] =>
I would request you to increase ssh timer (uncomment timeout line and set it to 60, whatever seconds you wish) in ansible.cfg file and observer this scenario.
# SSH timeout
#timeout = 300
Try this one:
- hosts: application
become: yes
become_exe: "sudo su - appadmin"
become_method: su
tasks:

ansible user current user in configuration

I am using ansible to configure the several computers after installation.
For this I run ansible locally on the machines. The "main" user on the installation has often a different name. I want to use that user for variables like become_user. The "main" user is also the user, who calls ansible-playbook.
So can I somehow set "become_user" to the user who called ansible-playbook?
Not sure why you need to set become_user to user you are already running your playbook with, but you can use env lookup to get USER environment variable:
- hosts: localhost
tasks:
- debug: msg="{{ lookup('env','USER') }}"
You can logon locally on control host as 'nathan', but want to connect to other servers as user 'ansible' (better in ansible.cfg)
remote_user = ansible
If you want on remote host connect as 'ansible' and perform one task as root or apache -- then sudo to root (apache or other user) you should use become_user for this particular task.
Please note also, than remote server may NOT have such user as on control host! (In common way)
In your particular case if you logon locally as 'nathan' and want to connect to 'remote' server as 'nathan' you should omit both remote_user and become_user: just logon with your current credentials!
For example, there's two sysadminst in organization: nathan and peter -- so, there's two workstation (heidelberg-nathan and berlin-peter) as ansible control host and thousands clients. Both nathan and peter connect to remote side as nathan or peter and perform tasks. Each of them can non-password sudoers to perform admin tasks.
PS Ok, let's test both solution (first - from Konstantin Suvorov's answer, second -- from knowhy's answer).
My control host berlin-ansible-01, i'm logged in as 'nathan'. Remote client is host berlin-client-01. I will log into client host as user 'ansible'.
My ansible.cfg is:
[defaults]
sudo_flags=-HE
hash_behaviour = merge
retry_files_enabled = false
log_path = ./main.log
ask_vault_pass=true
remote_user = ansible
Playbook is simple:
- name: test
hosts: '{{ target }}'
tasks:
- debug: msg="step 1 = {{ lookup('env','USER') }}"
- setup:
- debug: msg="step 2 = {{ hostvars[target].ansible_env.USER }}"
#more than one client in taget needs iterate items:
# - debug: msg="step 2 = {{ hostvars[item].ansible_env.USER }}"
# with_items: "{{ hostvars }}"
Let's run it:
[nathan#berlin-ansible-01 stackoverflow]$ ansible-playbook -i hosts_staging test.yml --extra-vars "target=berlin-client-01"
Vault password:
PLAY [test] ********************************************************************
TASK [setup] *******************************************************************
ok: [berlin-client-01]
TASK [debug] *******************************************************************
ok: [berlin-client-01] => {
"msg": "step 1 = nathan"
}
TASK [setup] *******************************************************************
ok: [berlin-client-01]
TASK [debug] *******************************************************************
ok: [berlin-client-01] => {
"msg": "step 2 = ansible"
}
PLAY RECAP *********************************************************************
berlin-client-01 : ok=4 changed=0 unreachable=0 failed=0
ansible-playbook provides the --become-user CLI flag along with --ask-become-pass (if needed).
In most cases, this is a bad setup. You should standardize the user on all of your machines else you'll have to maintain certs/passwords for each user separately.
There is no need to set become_user when the playbook should run with the user who started ansible-playbook
become is for privilege escalation. If I got this question right privilege escalation is not needed.
The name of the user which runs the playbook is available as an ansible fact {{ ansible_env.username }}

run ansible playbook with sudo

I have a playbook and I want to run it with sudo. It is my ansible playbook:
site.yml
---
- name: Server
hosts: node1
sudo: yes
roles:
- dbserver
When I run it I get this:
ansible-playbook -i hosts site.yml
PLAY [Server] *****************************************************************
GATHERING FACTS ***************************************************************
fatal: [node1] => Missing sudo password
TASK: [dbserver | installing server] ******************************************
FATAL: no hosts matched or all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit #/home/robe/site.retry
node1 : ok=0 changed=0 unreachable=1 failed=0
Then I add the ansible sudo pass on site.yml:
---
- name: Server
hosts: node1
sudo_pass: ubuntu
roles:
- dbserver
I get this error:
ERROR: sudo_pass is not a legal parameter at this level in an Ansible Playbook
Then my questions are:
Do I have add to each tasks the ansible sudo_pass attribute?
Is there any way to say sudo and sudo_pass in the playbook?
sudo_pass is not something Ansible knows. If you need to enter a sudo password on node1, then you keep sudo: yes in the playbook, and you'll have to give Ansible the sudo password on the commandline when running your playbook:
ansible-playbook -i hosts site.yml -K
Note the -K parameter. It will then ask you for the sudo password before the playbook starts.
(the long version is --ask-sudo-pass by the way. I had to look that up)

Resources