Thursday, September 06, 2018

Ansible: How to become a different person

I'm not going waste my breath to tell you about gorgeous ansible tool. With some efforts, it may help even old-school Oracle administrators and architects. The ansible is the total novelty for me, however learning curve is not steep, and even tiny virtual machine and community edition will open you the whole new world of YML (which I decipher as Yet Another XML), Y2 templates, and playbooks.
When I've done with a series of a "Hello world!" examples, I run into first of the real world issues. In the distilled examples, you have full access to the privileged account, like root password or you have passwordless sudo access to run commands and shell scripts. In reality, you have the only option: switch to the elevated user.
Your permission in the /etc/sudoers file looks similar to the example below:

 mmikhailidi     ALL=(root)      NOPASSWD: /bin/su - oracle
 mmikhailidi     ALL=(root)      NOPASSWD: /bin/su - jboss


s
As a result, I can execute only two privileged commands: become oracle or jboss. Any alterations are blocked or require a  password, you shouldn't have by security policies.
Naturally, you can use ansible with your credentials, but to do something useful with Fusion Middleware or Oracle database you should have access to the oracle. Needless to say, I've tried to google solution, and have found almost nothing. Almost, because this comment on GitHub gives me a tip, my special thanks to the Christoph Hösler.
The idea is simple, with the ansible we distribute the script, to become a privileged user and then execute the ansible commands. To implement this your ansible should support become_exe parameter. I  copy/pasted the script form the comment and of course, it doesn't work. Well, I know shell scripting well enough to figure out what's going on. and one more tip: use ansible with the -v options, and more vs will give you better visibility. You'd forgive me if I skip the whole debug process, so somewhere on the level -vvvv  I found the root cause and slightly improved Christoph's command. My final code of the ~/bin/asuser script has only a few lines left and allows you to use become_user option.

  #!/bin/bash
  # Skip 'sudo username -c' part
  shift
  # but keep user name
  user=$1;
  shift 2
  # Execute the rest
  sudo su - $user << END
   $@
  END

I run ansible on the single  VM so there are only a few entries in the inventory.  Let's take a look and discuss what is here:
[local]
  localhost
[elevated]
  fed28.vb.mmikhail.com
[jboss]
  fed28

[elevated:vars]
   ansible_become=true
   ansible_become_method=su
   ansible_become_exe="~/bin/asuser sudo"
   ansible_become_user=oracle

[jboss:vars]
   ansible_become=true
   ansible_become_method=su
   ansible_become_exe="~/bin/asuser sudo"
   ansible_become_user=jboss

My inventory contains 3 groups, two of them with elevated access. For all hosts in the group elevated and jboss ansible will apply variables declared in the corresponding var groups.
  • ansible_become=true   - Tells ansible that for this host(-s) other user is required. 
  • ansible_become_method=su - Defines the method of the user switch. There are plenty of the options. Particular value depends on the controlled host OS and configuration.
  • ansible_become_exe="~/bin/asuser sudo"  - The main variable in the configuration. It tells ansible to call my script on the controlled host. The script should be in the user's home folder.
  • ansible_become_user=   -  Provides ansible with the target username 
I put all the parameters in the inventory, In fact, all the common values could be moved to the ansible.cfg under "privilege escalation".

[privilege escalation]
   become=true
   become_method=su
   become_exe="~/bin/asuser sudo"

Nov, the inventory could be compacted to:

[local]
  localhost
[elevated]
  fed28.vb.mmikhail.com ansible_become_user=oracle

[jboss]
  fed28 ansible_become_user=jboss
  

Let's test the access to the shell and see the results.

As you see ansible runs shell scripts and commands with the requested privileges, even if you are allowed to execute only sudo su -  <user>.

Naturally, there is quite a space for the improvements:
  1. Get the script form version control system and distribute it with the ansible.  
  2. Wrap #1 into the role and use it with the playbooks. 
  3. There is a good chance that I've just reinvented a bicycle and ansible has the magic combination, that will work without my script. 
Give me your feedback and spread the word if you find this piece useful.

2 comments:

Unknown said...

Hi Mike,
Any idea how to achieve the same thing when sudo su - oracle requires a password?
Thanks,
--
Abbas

Unknown said...

Hi Mike,

I have found the solution, asuser should be:

$ cat ~/bin/asuser
#!/bin/bash
# Skip 'sudo username -c' part
shift
# but keep user name
user=$1;
shift 2
# Execute the rest
sudo -p "Password: " su - $user << END
$@
END

Regards,
--
Abbas