Ansible и restricted sudo

Здесь я хотел бы поделиться мыслями по поводу использования ansible2.1 в среде с ограниченными sudo правами (ansible+limited sudo), a именно использование ansible пользователями у которых есть только ограниченный набор sudo команд. К таким пользователям можно отнести например, девелоперов и саппорот команды. Особенно яркое разделение ролей можно увидеть в крупных компаниях, где есть например админы с root правами (отвечают за инфраструктуру и provisioning серверов), где есть operations команды (отвечают за поддержку приложений, баз данных и т.д), девелоперы (отвечают за деплой и траблшутинг приложений). У этих “бесправных” пользователей есть определенный набор sudo команд, которых в принципе достаточно для выполнения своих задач. Но когда ферма приложения состоит из 50 серверов и хостится где-нибудь в AWS+Autoscaling, и есть необходимость отрестартить сервис, то ansible с его AWS инвентори сильно облегчит работу. Но как я уже упомянул есть проблема, а именно если пользователю разрешен только ограниченный набор sudo команд, то использование ansible не всегда будет возможным, т.к ansible отсылает на сервер Python код который нужно выполнить, а /usr/bin/python не добавлен в sudo. Можно попробовать использовать модуль raw, но и тут есть проблема, ansible попытается  выполнить команду через /bin/sh –c, а /bin/sh или /bin/bash также не добавлены в sudo.

Это можно увидеть если запустить ansible с –vvv ключем.

[roonyk@ ansible]$ ansible hosts -m raw -a "/bin/netstat -ltupn" --become --ask-become-pass -k -vvv
Using /home/roonyk/ansible/ansible.cfg as config file
SSH password: 
SUDO password[defaults to SSH password]: 
<10.242.39.205> ESTABLISH SSH CONNECTION FOR USER: roonyk
<10.242.39.205> SSH: EXEC sshpass -d11 ssh -C -q -o ControlMaster=auto -o ControlPersist=1800s -o User=roonyk -o ConnectTimeout=10 -o ControlPath=/home/roonyk/.ansible/cp/%h-%r -tt 10.242.39.205 'sudo -H -S  -p "[sudo via ansible, key=zjzgvjphdogumqoudyuncoypfwlabpvu] password: " -u root /bin/bash -c '"'"'echo BECOME-SUCCESS-zjzgvjphdogumqoudyuncoypfwlabpvu; /bin/netstat -ltupn'"'"''
10.242.39.205 | FAILED | rc=1 >>

Sorry, user roonyk is not allowed to execute '/bin/bash -c echo BECOME-SUCCESS-zjzgvjphdogumqoudyuncoypfwlabpvu; /bin/netstat -ltupn' as root on ip-10-242-39-205.us-east-1.aws.cloud.test.com.
[roonyk@ ansible]$
 

Можно попросить администраторов добавить /usr/bin/python и /bin/bash в sudo, но по различным причинам они скорее всего не согласятся на это (особенно в крупных компаниях).

Но можно попробовать написать свой connection plugin который немного переопределит метод make_become_cmd отвечающий за формат засылаемых команд.

В моем случае это файлик ssh_sudo.py который необходимо поместить в папку connection_plugins и добавить путь к этой папке в конфигурационном файле. Также в конфигурационном файле в качестве транспорта указать свой свой ssh_sudo.

transport      = ssh_sudo
connection_plugins = ./connection_plugins

 

Код самого плагина – файл ssh_sudo.py :

import ansible.constants as C
import ansible.plugins.connection.ssh as SSH
import pipes

class Connection (SSH.Connection):

    def __init__(self, play_context, *args, **kwargs):

        super (Connection, self).__init__(play_context, *args, **kwargs)        
        
        self._make_become_cmd = self._play_context.make_become_cmd
        self._play_context.make_become_cmd = self.make_become_cmd
        

    def make_become_cmd (self, cmd, executable = None):
      
        becomecmd = self._make_become_cmd(cmd, executable=None)

        if cmd.split('=')[0] == 'sudo':
            
            command = cmd.split('=')[1]
            exe = self._play_context.become_method
            flags = getattr(C, 'DEFAULT_%s_FLAGS' % self._play_context.become_method.upper(), None)
            prompt = self._play_context.prompt
            user = self._play_context.become_user
            success_key = self._play_context.success_key         

            sudocmd = '%s -k && setsid %s %s-p "%s" -u %s %s;' 'rc=$?; echo %s; exit $rc' % \
                      (exe, exe, flags.replace('-n',''), prompt, user, command, success_key)
 
            becomecmd = '$SHELL -c ' + pipes.quote (sudocmd)
       
        return (becomecmd)

 

Теперь запустив ansible увидим что команда выполнилась.

[roonyk@EPBYMINW4969 ansible]$ ansible hosts -m raw -a "sudo=/bin/netstat -ltupn" --become --ask-become-pass -k -vvv
Using /home/roonyk/ansible/ansible.cfg as config file
SSH password: 
SUDO password[defaults to SSH password]: 
<10.242.39.205> ESTABLISH SSH CONNECTION FOR USER: roonyk
<10.242.39.205> SSH: EXEC sshpass -d11 ssh -C -q -o ControlMaster=auto -o ControlPersist=1800s -o User=roonyk -o ConnectTimeout=10 -o ControlPath=/home/roonyk/.ansible/cp/%h-%r -tt 10.242.39.205 '$SHELL -c '"'"'sudo -k && setsid sudo -H -S -p "[sudo via ansible, key=yfutrphrslijpnomjaxgqahoqiigoupt] password: " -u root /bin/netstat -ltupn;rc=$?; echo BECOME-SUCCESS-yfutrphrslijpnomjaxgqahoqiigoupt; exit $rc'"'"''
10.242.39.205 | SUCCESS | rc=0 >>

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 0.0.0.0:46911               0.0.0.0:*                   LISTEN      967/rpc.statd       
tcp        0      0 127.0.0.1:32000             0.0.0.0:*                   LISTEN      11717/java          
tcp        0      0 0.0.0.0:5666                0.0.0.0:*                   LISTEN      8227/nrpe           
tcp        0      0 127.0.0.1:199               0.0.0.0:*                   LISTEN      1069/snmpd          
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      927/rpcbind         
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1775/sshd           
tcp        0      0 0.0.0.0:25                  0.0.0.0:*                   LISTEN      3646/master         
tcp        0      0 :::5666                     :::*                        LISTEN      8227/nrpe           
tcp        0      0 :::43874                    :::*                        LISTEN      967/rpc.statd       
tcp        0      0 :::111                      :::*                        LISTEN      927/rpcbind         
tcp        0      0 :::80                       :::*                        LISTEN      7441/fcgi-          
tcp        0      0 :::22                       :::*                        LISTEN      1775/sshd           
udp        0      0 0.0.0.0:33151               0.0.0.0:*                               967/rpc.statd       
udp        0      0 0.0.0.0:161                 0.0.0.0:*                               1069/snmpd          
udp        0      0 0.0.0.0:678                 0.0.0.0:*                               927/rpcbind         
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               825/dhclient        
udp        0      0 127.0.0.1:719               0.0.0.0:*                               967/rpc.statd       
udp        0      0 0.0.0.0:111                 0.0.0.0:*                               927/rpcbind         
udp        0      0 10.242.39.205:123           0.0.0.0:*                               1675/ntpd           
udp        0      0 127.0.0.1:123               0.0.0.0:*                               1675/ntpd           
udp        0      0 0.0.0.0:123                 0.0.0.0:*                               1675/ntpd           
udp        0      0 :::678                      :::*                                    927/rpcbind         
udp        0      0 :::59621                    :::*                                    967/rpc.statd       
udp        0      0 :::111                      :::*                                    927/rpcbind         
udp        0      0 fe80::83a:72ff:fec6:c747:123 :::*                                    1675/ntpd           
udp        0      0 ::1:123                     :::*                                    1675/ntpd           
udp        0      0 :::123                      :::*                                    1675/ntpd           


[roonyk@ ansible]$

.

Комментарии

Чтобы оставить комментарий, необходимо Войти или Зарегистрироваться.