Chinaunix首页 | 论坛 | 博客
  • 博客访问: 351567
  • 博文数量: 52
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 577
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-27 14:21
个人简介

知道自己该干嘛,知道自己能干嘛

文章分类

全部博文(52)

文章存档

2019年(1)

2018年(8)

2017年(2)

2016年(11)

2015年(3)

2014年(10)

2013年(17)

我的朋友

分类: 系统运维

2018-08-09 15:30:02


          ansible作为自动化管理工具,对于运维人员来说ad-hoc是使用频率最高的一项功能,但是ad-hoc也有一些安全隐患,比如大规模批量误删除一些文件,修改等,为了避免此类情况的出现,从源码级别屏蔽危险命令,提高ansible的可靠性,啥都不说了,直接堆码。
          ansible版本: ansible 2.4.2.0

       修改/usr/lib/python2.7/site-packages/ansible/modules/commands/command.py

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. # (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>, and others
  4. # (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
  5. #
  6. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

  7. from __future__ import absolute_import, division, print_function
  8. __metaclass__ = type


  9. ANSIBLE_METADATA = {'metadata_version': '1.1',
  10.                     'status': ['stableinterface'],
  11.                     'supported_by': 'core'}

  12. DOCUMENTATION = '''
  13. ---
  14. module: command
  15. short_description: Executes a command on a remote node
  16. version_added: historical
  17. description:
  18.      - The C(command) module takes the command name followed by a list of space-delimited arguments.
  19.      - The given command will be executed on all selected nodes. It will not be
  20.        processed through the shell, so variables like C($HOME) and operations
  21.        like C("<"), C(">"), C("|"), C(";") and C("&") will not work (use the M(shell)
  22.        module if you need these features).
  23.      - For Windows targets, use the M(win_command) module instead.
  24. options:
  25.   free_form:
  26.     description:
  27.       - The command module takes a free form command to run. There is no parameter actually named 'free form'.
  28.         See the examples!
  29.     required: yes
  30.   creates:
  31.     description:
  32.       - A filename or (since 2.0) glob pattern, when it already exists, this step will B(not) be run.
  33.   removes:
  34.     description:
  35.       - A filename or (since 2.0) glob pattern, when it does not exist, this step will B(not) be run.
  36.     version_added: "0.8"
  37.   chdir:
  38.     description:
  39.       - Change into this directory before running the command.
  40.     version_added: "0.6"
  41.   warn:
  42.     description:
  43.       - If command_warnings are on in ansible.cfg, do not warn about this particular line if set to C(no).
  44.     type: bool
  45.     default: 'yes'
  46.     version_added: "1.8"
  47.   stdin:
  48.     version_added: "2.4"
  49.     description:
  50.       - Set the stdin of the command directly to the specified value.
  51.     required: false
  52.     default: null
  53. notes:
  54.     - If you want to run a command through the shell (say you are using C(<), C(>), C(|), etc), you actually want the M(shell) module instead.
  55.        The C(command) module is much more secure as it's not affected by the user's environment.
  56.     - " C(creates), C(removes), and C(chdir) can be specified after the command.
  57.        For instance, if you only want to run a command if a certain file does not exist, use this."
  58.     - The C(executable) parameter is removed since version 2.4. If you have a need for this parameter, use the M(shell) module instead.
  59.     - For Windows targets, use the M(win_command) module instead.
  60. author:
  61.     - Ansible Core Team
  62.     - Michael DeHaan
  63. '''

  64. EXAMPLES = '''
  65. - name: return motd to registered var
  66.   command: cat /etc/motd
  67.   register: mymotd

  68. - name: Run the command if the specified file does not exist.
  69.   command: /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database

  70. # You can also use the 'args' form to provide the options.
  71. - name: This command will change the working directory to somedir/ and will only run when /path/to/database doesn't exist.
  72.   command: /usr/bin/make_database.sh arg1 arg2
  73.   args:
  74.     chdir: somedir/
  75.     creates: /path/to/database

  76. - name: safely use templated variable to run command. Always use the quote filter to avoid injection issues.
  77.   command: cat {{ myfile|quote }}
  78.   register: myoutput
  79. '''

  80. import datetime
  81. import glob
  82. import os
  83. import shlex

  84. from ansible.module_utils.basic import AnsibleModule


  85. def check_command(module, commandline):
  86.     arguments = {'chown': 'owner', 'chmod': 'mode', 'chgrp': 'group',
  87.                  'ln': 'state=link', 'mkdir': 'state=directory',
  88.                  'touch': 'state=touch'}
  89.     commands = {'hg': 'hg', 'curl': 'get_url or uri', 'wget': 'get_url or uri',
  90.                 'svn': 'subversion', 'service': 'service',
  91.                 'mount': 'mount', 'rpm': 'yum, dnf or zypper', 'yum': 'yum', 'apt-get': 'apt',
  92.                 'tar': 'unarchive', 'unzip': 'unarchive', 'sed': 'template or lineinfile',
  93.                 'dnf': 'dnf', 'zypper': 'zypper'}
  94.     become = ['sudo', 'su', 'pbrun', 'pfexec', 'runas', 'pmrun']
  95.     forbidden = ['rm','rmdir']
  96.     command = os.path.basename(commandline.split()[0])
  97.     if command in arguments:
  98.         module.warn("Consider using file module with %s rather than running %s" % (arguments[command], command))
  99.         return True,""
  100.     if command in commands:
  101.         module.warn("Consider using %s module rather than running %s" % (commands[command], command))
  102.         return True,""
  103.     if command in become:
  104.         module.warn("Consider using 'become', 'become_method', and 'become_user' rather than running %s" % (command,))
  105.         return True,""
  106.     if command in forbidden:
  107.     # module.warn("Forbidden executable command %s, please contact ansible administrator" % (command,))
  108.         return False,command
  109.        
  110.     return True,""
  111. def main():

  112.     # the command module is the one ansible module that does not take key=value args
  113.     # hence don't copy this one if you are looking to build
  114.     module = AnsibleModule(
  115.         argument_spec=dict(
  116.             _raw_params=dict(),
  117.             _uses_shell=dict(type='bool', default=False),
  118.             chdir=dict(type='path'),
  119.             executable=dict(),
  120.             creates=dict(type='path'),
  121.             removes=dict(type='path'),
  122.             warn=dict(type='bool', default=True),
  123.             stdin=dict(required=False),
  124.         )
  125.     )

  126.     shell = module.params['_uses_shell']
  127.     chdir = module.params['chdir']
  128.     executable = module.params['executable']
  129.     args = module.params['_raw_params']
  130.     creates = module.params['creates']
  131.     removes = module.params['removes']
  132.     warn = module.params['warn']
  133.     stdin = module.params['stdin']

  134.     if not shell and executable:
  135.         module.warn("As of Ansible 2.4, the parameter 'executable' is no longer supported with the 'command' module. Not using '%s'." % executable)
  136.         executable = None

  137.     if args.strip() == '':
  138.         module.fail_json(rc=256, msg="no command given")

  139.     if chdir:
  140.         chdir = os.path.abspath(chdir)
  141.         os.chdir(chdir)

  142.     if creates:
  143.         # do not run the command if the line contains creates=filename
  144.         # and the filename already exists. This allows idempotence
  145.         # of command executions.
  146.         if glob.glob(creates):
  147.             module.exit_json(
  148.                 cmd=args,
  149.                 stdout="skipped, since %s exists" % creates,
  150.                 changed=False,
  151.                 rc=0
  152.             )

  153.     if removes:
  154.         # do not run the command if the line contains removes=filename
  155.         # and the filename does not exist. This allows idempotence
  156.         # of command executions.
  157.         if not glob.glob(removes):
  158.             module.exit_json(
  159.                 cmd=args,
  160.                 stdout="skipped, since %s does not exist" % removes,
  161.                 changed=False,
  162.                 rc=0
  163.             )

  164.     if warn:
  165.         res,cmd=check_command(module, args)
  166.    
  167.     if not shell:
  168.         args = shlex.split(args)
  169.     startd = datetime.datetime.now()
  170.     
  171.     if res:
  172.         rc, out, err = module.run_command(args, executable=executable, use_unsafe_shell=shell, encoding=None, data=stdin)
  173.     else:
  174.         out,err,rc = "","",250

  175.     endd = datetime.datetime.now()
  176.     delta = endd - startd

  177.     if out is None:
  178.         out = b''
  179.     if err is None:
  180.         err = b''

  181.     result = dict(
  182.         cmd=args,
  183.         stdout=out.rstrip(b"\r\n"),
  184.         stderr=err.rstrip(b"\r\n"),
  185.         rc=rc,
  186.         start=str(startd),
  187.         end=str(endd),
  188.         delta=str(delta),
  189.         changed=True,
  190.     )
  191.     
  192.     if rc != 0:
  193.         if rc == 250:
  194.         module.fail_json(msg='Forbidden executable command {}, please contact ansible administrator'.format(cmd), **result)
  195.         else:
  196.         module.fail_json(msg='non-zero return code', **result)
  197.     module.exit_json(**result)


  198. if __name__ == '__main__':
  199.     main()
         
            
想屏蔽的命令直接添加到forbidden列表里即可,效果演示:




                                                                                                                   umapy_Cail


阅读(2221) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~