Disable manual login access to ansible remote user - linux

I have a project that requires me to setup a user who can run specific tasks in ansible but said user shouldn't be able to login to the server from the command line.
The reason for this is management wants non administrators to be able to run certain tasks using ansible without direct login access.
In other words, running the task below should be possible for non administrators
- hosts: target_server
remote_user: ansible
tasks:
- name: user name
shell: whoami
become: no
changed: [192.168.2.3] => {
"changed": true,
"cmd": "whoami",
"delta": "0:00:00.004776",
"end": "2017-07-20 00:31:36.637252",
"invocation": {
"module_args": {
"_raw_params": "whoami",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
}
},
"rc": 0,
"start": "2017-07-20 00:31:36.632476",
"stderr": "",
"stderr_lines": [],
"stdout": "ansible",
"stdout_lines": [
"ansible"
]
}
However non administrators should not be able to do this.
ssh ansible#192.168.2.3
Last login: Thu Jul 20 00:39:11 2017 from 192.168.2.5
[ansible#192.168.2.3 ~]$
Any ideas on how to implement this or whether it's even possible?

Ansible pretty much requires a login to operate properly due to how it executes shell commands to do its work. I'm not sure you can reasonably restrict a user that's supposed to have a lot of latitude in what it can do.
You may need to use something other than Ansible, maybe a tool that has a server-side agent that runs the jobs, where no external login is needed.
Another approach might be to secure Ansible itself behind some kind of security layer, where the actual Ansible initiation is done by a trusted user that the end-users do not have access to.
This could be via some kind of shell, Python or Ruby script that signals to a background process to perform Ansible tasks, or via a web interface where your people click a button to start the process and the background task takes over.

No, this is not possible in general. Ansible uses the same ssh command under the hood.
Consider using dedicated box with some web/cli interface for non-admin folks to execute jobs. See rundeck or tower for example.

Related

Ansible service module returns service status as stopped when the service is actually running

Trying to stop a service (dse datastax enterprise) using ansible 2.7
- name: Stop service dse, if started
service:
name: dse
state: stopped
What I think ansible is saying is, I'm not doing anything because this service is already stopped. Part of the verbose output:
ok: [myhostname.domain.com] => {
"changed": false,
"invocation": {
"module_args": {
"daemon_reload": false,
"enabled": null,
"force": null,
"masked": null,
"name": "dse",
"no_block": false,
"scope": null,
"state": "stopped",
"user": null
}
},
"name": "dse",
"state": "stopped",
When I check the service on the remote host this is what I see
[user#remotehost ~]$ service dse status
dse is running
So what am I missing here?
FYI it's recommended doing a sudo service dse stop for this service, I don't know if lack of the sudo will make such a difference.
My understanding of this is since I do not have an unrestricted sudo and I do not have the ability to execute in /bin/sh thus it is failing.
The same command works when directly run on the server, and that is because
Ansible sends Python code to be executed on the targeted servers. Since Ansible is running Python code and generally not executing system commands directly, you can't limit system commands with sudo and expect them to work with Ansible.
More: https://gist.github.com/nanobeep/3b3d614a709086ff832a
Not sure everyone has this luxury but in my case modifying the sudoers file
from
TheGroupNameImPartOf ALL= ALL, !SU, !SHELLS
to
TheGroupNameImPartOf ALL= ALL
Did the magic!

Chef node not consistently saving run list on server during first boot - Azure Scale set VM

I'm presently hosting an Azure Scale set running Windows Server 2012 R2 that is setup with the Chef extension (Chef.Bootstrap.WindowsAzure.ChefClient). When the VM is provisioned, the extension reports back that it succeeded via the Azure portal however the registered node on the Chef server is not updated to retain the provided run list and the first run isn't fully completed. This is causing subsequent chef-client runs to be performed with an empty run list. When I observe the reports on chef server, I see a run with a status of aborted with no error.
Upon review of the WindowsAzure Plugins chef-client.log file, I can see that it tries to execute the run list but seems to be interrupted with the following FATAL
FATAL: Errno::EINVAL: Invalid argument # io_writev - <STDOUT>
There is no chef-stacktrace.out file created as well. The ARM extension definition looks like:
{
"type": "extensions",
"name": "ChefClient",
"properties": {
"publisher": "Chef.Bootstrap.WindowsAzure",
"type": "ChefClient",
"typeHandlerVersion": "1210.12",
"autoUpgradeMinorVersion": true,
"settings": {
"client_rb": "ssl_verify_mode :verify_none\nnode_name ENV[\"COMPUTERNAME\"]",
"runlist": "recipe[example]",
"autoUpdateClient": "false",
"deleteChefConfig": "false",
"bootstrap_options": {
"chef_server_url": "https://mychefserver.com/organizations/myorg",
"validation_client_name": "myorg-validator",
"environment": "dev"
}
},
"protectedSettings": {
"validation_key": "-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY----"
}
}
}
In order to troubleshoot, I've tried to reduce my example cookbook down to a single DSC script which installs IIS. Even this step, I've executed it multiple ways such as using windows_feature, powershell_script, and dsc_script. All result end up with the same error. Here is the current script
powershell_script 'Install IIS' do
code 'Add-WindowsFeature Web-Server'
guard_interpreter :powershell_script
not_if "(Get-WindowsFeature -Name Web-Server).Installed"
end
If I override the run list and call chef-client manually, everything succeeds. I'm having trouble honing in on whether this is the Azure Chef Extension, the Chef client, or the cookbook.
As far as I can tell, communication with the Chef server looks good as the necessary pem files are exchanged, chef-client is installed, and the cookbook is downloaded and cached from the server. The cache gets removed on the subsequent run however with the empty run list. Here are the contents of first-boot.json:
{"run_list":["recipe[example]"]}
Here are the versions in play:
chef-client version: 14.1.12
Azure Chef Extension version: 1210.12.110.1001
Server version: Windows Server 2012 R2
Any ideas what could be going on?
It turns out my analysis was incorrect about which resource was causing the problem. It appears that the first boot run was failing when using dsc_script as the resource to install the web server. When using the following powershell_script resource, it succeeded and the run list attached for future runs.
powershell_script 'Install IIS' do
code 'Add-WindowsFeature Web-Server'
guard_interpreter :powershell_script
not_if "(Get-WindowsFeature -Name Web-Server).Installed"
end

ansible 2.3> while check on windows hosts, error: Thread failed to start

I am connecting to windows host via ansible. But I am getting from win_shell an error.
[as_user#tt ansible-winconnect]$ ansible-playbook -i WIN win_conn.yml -t echo_test --ask-pass -vvvv
fatal: [x.x.x.x]: FAILED! => {
"changed": true,
"cmd": "echo %HOMEDIR% > print.txt",
"delta": "0:00:00.287028",
"end": "2017-05-25 11:38:05.603907",
"failed": true,
"rc": 1,
"start": "2017-05-25 11:38:05.316878",
"stderr": "Thread failed to start.\r\n",
"stderr_lines": [
"Thread failed to start."
],
"stdout": "",
"stdout_lines": []
}
[as_user#tt ansible-winconnect]$ cat win-conn/tasks/main.yml
---
- name: Print Home Dir in a file
win_shell: echo %HOMEDIR% > print.txt
tags: echo_test
Assuming you have powershell 3+ and you followed the Ansible docs you very well maybe be running into an out of memory issue. According to Microsoft
The issue occurs because the Windows Remote Management (WinRM) service does not use the customized value of the MaxMemoryPerShellMB quota. Instead, the WinRM service uses the default value, which is 150 MB.
The shell created by WinRM might not have enough memory in order to run the powershell that Ansible is trying to run via WinRM.
Try using the following hotfix from Microsoft https://support.microsoft.com/en-us/help/2842230/out-of-memory-error-on-a-computer-that-has-a-customized-maxmemorypersh
Do you know which version of powershell your host machine is using? Try upgrading to version 4 or above and see if that fixes the error. Or you could also try running that command with the win_command or raw ansible modules.

Ansible fails to pass parameters when executing a .run file

I am trying to use Ansible to install a .run file (created using Makeself 2.1.5) using the following task in a playbook:
- name: Install Program
command: /home/user/folder/program.run -- /S /D=/home/user/folder/destination/
Here, /S is a switch to run a silent installation and the parameter /D sets the destination for the installation. Running this command in the console succeeds.
Ansible claims to run the task without error:
changed: [127.0.0.1] => {
"changed": true,
"cmd": [
"/home/user/folder/program.run",
"--",
"/S",
"/D=/home/user/folder/destination/"
],
"delta": "0:00:00.065261",
"end": "2017-01-06 09:08:43.114265",
"invocation": {
"module_args": {
"_raw_params": "/home/user/folder/program.run -- /S /D=/home/user/folder/destination/",
"_uses_shell": false,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"rc": 0,
"start": "2017-01-06 09:08:43.049004",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings" : []
So somehow the additional parameters cause the execution to fail without Ansible noticing. I've tried using the shell command and various ways of quoting my command, but to no avail.
If I do not pass parameters to the .run file, that is use command: /home/user/folder/program.run, an installation prompt is opened asking for user input, which defeats the purpose of Ansible.
Does anybody have a solution for this? A possible workaround might be to use the expect module, but I would prefer to be able to use the command line arguments, as this is not the only file I would like to install.
I am using Ansible 2.2.0.0 on Ubuntu 16.04.1 LTS.
EDIT:
Following techraf's advice, I found a simple solution using the shell module. Using shell: konsole -e /home/user/folder/program.run /S /D=/home/user/folder/destination/ caused the installation to complete correctly. It is also possible to put the command in a script file and run it using the script module.
Try using the shell module instead of command:
- name: Install Program
shell: /home/user/folder/program.run -- /S /D=/home/user/folder/destination/
You are using -- in the command execution, which actually prevents shell form parsing the arguments that follow. It's a shell built-in, not a parameter of the command.
Can't test it now (and frankly showing without the real program you run it's impossible), but I bet it should work.
If the above won't work, you'd probably have to put this line in a script and run it with the script module.

How to run supervisor with Ansible?

I've got a server on which Supervisord is managing my processes. I normally start supervisord with the following command:
sudo /var/www/imd/venv/bin/supervisord -c /var/www/imd/deploy/supervisord.conf
I'm now trying to set things up with Ansible, but I'm unsure of how I should start Ansible. I can of course do it using something like:
- name: run supervisord
command: "/var/www/imd/venv/bin/supervisord -c /var/www/imd/deploy/supervisord.conf"
This works, but only the first time that you run it. Second time you run the same script supervisord is of course already running, which causes the following error:
TASK [run supervisord]
******************************************************* fatal: [ansible-test1]: FAILED! => {"changed": true, "cmd":
["/var/www/imd/venv/bin/supervisord", "-c",
"/var/www/imd/deploy/supervisord.conf"], "delta": "0:00:00.111700",
"end": "2016-06-03 11:57:38.605804", "failed": true, "rc": 2, "start":
"2016-06-03 11:57:38.494104", "stderr": "Error: Another program is
already listening on a port that one of our HTTP servers is configured
to use. Shut this program down first before starting
supervisord.\nFor help, use /var/www/imd/venv/bin/supervisord -h",
"stdout": "", "stdout_lines": [], "warnings": []}
Does anybody know how I can correctly run supervisord with Ansible? All tips are welcome!
[EDIT]
Because the solution in the answer by mbarthelemy doesn't work for socket files I now managed to get it working with the following:
- name: run supervisord
shell: if [ ! -S /var/run/supervisor.sock ]; then sudo /var/www/imd/venv/bin/supervisord -c /var/www/imd/deploy/supervisord.conf; fi
This of course is not very "ansibleish". If anybody has a real Ansible-based solution that would still be really welcome.
You can use supervisor module
- supervisorctl:
name: my_app
state: restarted
config: /var/opt/my_project/supervisord.conf
or
- name: Restart my_app
supervisorctl:
name: my_app
state: restarted
config: /var/opt/my_project/supervisord.conf
full documentation on https://docs.ansible.com/ansible/2.7/modules/supervisorctl_module.html#examples
Your situation is specific since you don't seem to use a regular Supervisor installed as a normal system package ; in that case you would start/stop/restart it like any other regular system service, using Ansible's service module.
By default, upon starting Supervisor creates a socket to listen for administrations commands from supervisorctl. When it stops it it supposed to remove it.
Try to find where this socket is created in your specific setup (default would be /var/run/supervisor.sock).
Then, let the Ansible command module know that if the Suopervisord process is already running, the socket exists, using the creates option (documentation). This way it won't try to run the command if it's already running:
- name: run supervisord
command: "./venv/bin/supervisord -c ./deploy/supervisord.conf"
args:
chdir=/var/www/imd
creates=/var/run/supervisor.sock
Edit : while this would be the right answer if /var/run/supervisor.sock were a file, it won't work because it's a socket, and Ansible's create parameter won't work.
The most Ansible-ish solution I can think of is using an external Ansible module like one of these, to check if you process already exists (test_process) or is already listening (test_tcp)

Resources