From f9f99ddfbc092adae5aaf686975ee53a0bac099d Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 10 Jan 2017 11:17:33 -0500 Subject: [PATCH] updated docs to suggest quote filter for shells Also changed comments into -name in examples where appropriate. --- docs/docsite/rst/playbooks_lookups.rst | 77 ++++++++++++++----------- lib/ansible/modules/commands/command.py | 29 +++++----- lib/ansible/modules/commands/raw.py | 16 ++--- lib/ansible/modules/commands/shell.py | 24 ++++---- 4 files changed, 79 insertions(+), 67 deletions(-) diff --git a/docs/docsite/rst/playbooks_lookups.rst b/docs/docsite/rst/playbooks_lookups.rst index 3014555f877..9048371e97a 100644 --- a/docs/docsite/rst/playbooks_lookups.rst +++ b/docs/docsite/rst/playbooks_lookups.rst @@ -14,6 +14,8 @@ in Ansible, and are typically used to load variables or templates with informati .. note:: Since 1.9 you can pass wantlist=True to lookups to use in jinja2 template "for" loops. +.. warning:: Some lookups pass arguments to a shell, if using variables from a remote/untrusted source use the `|quote` filter to ensure safe usage. + .. contents:: Topics .. _getting_file_contents: @@ -60,10 +62,11 @@ This length can be changed by passing an extra parameter:: tasks: - # create a mysql user with a random password: - - mysql_user: name={{ client }} - password="{{ lookup('password', 'credentials/' + client + '/' + tier + '/' + role + '/mysqlpassword length=15') }}" - priv={{ client }}_{{ tier }}_{{ role }}.*:ALL + - name: create a mysql user with a random password + mysql_user: + name: "{{ client }}" + password: "{{ lookup('password', 'credentials/' + client + '/' + tier + '/' + role + '/mysqlpassword length=15') }}" + priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL" # (...) @@ -78,20 +81,20 @@ Starting in version 1.4, password accepts a "chars" parameter to allow defining tasks: - # create a mysql user with a random password using only ascii letters: - - mysql_user: name={{ client }} - password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters') }}" - priv={{ client }}_{{ tier }}_{{ role }}.*:ALL + - name: create a mysql user with a random password using only ascii letters + mysql_user: name={{ client }} password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters') }}" priv={{ client }}_{{ tier }}_{{ role }}.*:ALL - # create a mysql user with a random password using only digits: - - mysql_user: name={{ client }} - password="{{ lookup('password', '/tmp/passwordfile chars=digits') }}" - priv={{ client }}_{{ tier }}_{{ role }}.*:ALL + - name: create a mysql user with a random password using only digits + mysql_user: + name: "{{ client }}" + password: "{{ lookup('password', '/tmp/passwordfile chars=digits') }}" + priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL" - # create a mysql user with a random password using many different char sets: - - mysql_user: name={{ client }} - password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters,digits,hexdigits,punctuation') }}" - priv={{ client }}_{{ tier }}_{{ role }}.*:ALL + - name: create a mysql user with a random password using many different char sets + mysql_user: + name: "{{ client }}" + password" "{{ lookup('password', '/tmp/passwordfile chars=ascii_letters,digits,hexdigits,punctuation') }}" + priv: "{{ client }}_{{ tier }}_{{ role }}.*:ALL" # (...) @@ -436,8 +439,7 @@ Since there are too many parameters for this lookup method, below is a sample pl tasks: - debug: msg="Mongo has already started with the following PID [{{ item.pid }}]" - with_items: - - "{{ lookup('mongodb', mongodb_parameters) }}" + with_mongodb: "{{mongodb_parameters}}" @@ -475,8 +477,7 @@ More Lookups Various *lookup plugins* allow additional ways to iterate over data. In :doc:`Loops ` you will learn how to use them to walk over collections of numerous types. However, they can also be used to pull in data -from remote sources, such as shell commands or even key value stores. This section will cover lookup -plugins in this capacity. +from remote sources, such as shell commands or even key value stores. This section will cover lookup plugins in this capacity. Here are some examples:: @@ -487,22 +488,29 @@ Here are some examples:: - debug: msg="{{ lookup('env','HOME') }} is an environment variable" - - debug: msg="{{ item }} is a line from the result of this command" - with_lines: - - cat /etc/motd + - name: lines will iterate over each line from stdout of a command + debug: msg="{{ item }} is a line from the result of this command" + with_lines: cat /etc/motd - debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command" - # redis_kv lookup requires the Python redis package - - debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey" + - name: Always use quote filter to make sure your variables are safe to use with shell + debug: msg="{{ lookup('pipe','getent ' + myuser|quote ) }}" + + - name: Quote variables with_lines also as it executes shell + debug: msg="{{ item }} is a line from myfile" + with_lines: "cat {{myfile|quote}}" + + - name: redis_kv lookup requires the Python redis package + debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey" - # dnstxt lookup requires the Python dnspython package - - debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com" + - name: dnstxt lookup requires the Python dnspython package + debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com" - debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template" - # loading a json file from a template as a string - - debug: msg="{{ lookup('template', './some_json.json.j2', convert_data=False) }} is a value from evaluation of this template" + - name: loading a json file from a template as a string + debug: msg="{{ lookup('template', './some_json.json.j2', convert_data=False) }} is a value from evaluation of this template" - debug: msg="{{ lookup('etcd', 'foo') }} is a value from a locally running etcd" @@ -518,13 +526,12 @@ Here are some examples:: # outputs the cartesian product of the supplied lists - debug: msg="{{item}}" with_cartesian: - - list1 - - list2 - - list3 + - "{{list1}}" + - "{{list2}}" + - [1,2,3,4,5,6] -As an alternative you can also assign lookup plugins to variables or use them -elsewhere. This macros are evaluated each time they are used in a task (or -template):: +As an alternative you can also assign lookup plugins to variables or use them elsewhere. +This macros are evaluated each time they are used in a task (or template):: vars: motd_value: "{{ lookup('file', '/etc/motd') }}" diff --git a/lib/ansible/modules/commands/command.py b/lib/ansible/modules/commands/command.py index 9b8afe3ef58..78fd16aa4dc 100644 --- a/lib/ansible/modules/commands/command.py +++ b/lib/ansible/modules/commands/command.py @@ -71,30 +71,33 @@ options: - if command warnings are on in ansible.cfg, do not warn about this particular line if set to no/false. required: false notes: - - 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. The - M(command) module is much more secure as it's not affected by the user's - environment. - - " C(creates), C(removes), and C(chdir) can be specified after the command. For instance, if you only want to run a command if a certain file does not exist, use this." + - 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. + The M(command) module is much more secure as it's not affected by the user's environment. + - " C(creates), C(removes), and C(chdir) can be specified after the command. + For instance, if you only want to run a command if a certain file does not exist, use this." author: - Ansible Core Team - Michael DeHaan ''' EXAMPLES = ''' -# Example from Ansible Playbooks. -- command: /sbin/shutdown -t now +- name: return motd to registered var + command: cat /etc/motd + register: mymotd -# Run the command if the specified file does not exist. -- command: /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database +- name: Run the command if the specified file does not exist. + command: /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database -# You can also use the 'args' form to provide the options. This command -# will change the working directory to somedir/ and will only run when -# /path/to/database doesn't exist. -- command: /usr/bin/make_database.sh arg1 arg2 +# You can also use the 'args' form to provide the options. +- name: This command will change the working directory to somedir/ and will only run when /path/to/database doesn't exist. + command: /usr/bin/make_database.sh arg1 arg2 args: chdir: somedir/ creates: /path/to/database + +- name: safely use tempalated variable to run command. Always use the quote filter to avoid injection issues. + command: cat {{ myfile|quote }} + register: myoutput ''' import datetime diff --git a/lib/ansible/modules/commands/raw.py b/lib/ansible/modules/commands/raw.py index a6ae0f8366a..2bf724e77e7 100644 --- a/lib/ansible/modules/commands/raw.py +++ b/lib/ansible/modules/commands/raw.py @@ -64,15 +64,17 @@ author: ''' EXAMPLES = ''' -# Bootstrap a legacy python 2.4 host -- raw: yum -y install python-simplejson +- name: Bootstrap a legacy python 2.4 host + raw: yum -y install python-simplejson -# Bootstrap a host without python2 installed -- raw: dnf install -y python2 python2-dnf libselinux-python +- name: Bootstrap a host without python2 installed + raw: dnf install -y python2 python2-dnf libselinux-python -# Run a command that uses non-posix shell-isms (in this example /bin/sh -# doesn't handle redirection and wildcards together but bash does) -- raw: cat < /tmp/*txt +- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but bash does) + raw: cat < /tmp/*txt args: executable: /bin/bash + +- name: safely use templated variables. Always use quote filter to avoid injection issues. + raw: {{package_mgr|quote}} {{pkg_flags|quote}} install {{python_simplejson|quote}} ''' diff --git a/lib/ansible/modules/commands/shell.py b/lib/ansible/modules/commands/shell.py index 93d187b81ec..a29623a5ec8 100644 --- a/lib/ansible/modules/commands/shell.py +++ b/lib/ansible/modules/commands/shell.py @@ -82,28 +82,28 @@ author: ''' EXAMPLES = ''' -# Execute the command in remote shell; stdout goes to the specified -# file on the remote. -- shell: somescript.sh >> somelog.txt +- name: Execute the command in remote shell; stdout goes to the specified file on the remote. + shell: somescript.sh >> somelog.txt -# Change the working directory to somedir/ before executing the command. -- shell: somescript.sh >> somelog.txt +- name: Change the working directory to somedir/ before executing the command. + shell: somescript.sh >> somelog.txt args: chdir: somedir/ -# You can also use the 'args' form to provide the options. This command -# will change the working directory to somedir/ and will only run when -# somedir/somelog.txt doesn't exist. -- shell: somescript.sh >> somelog.txt +# You can also use the 'args' form to provide the options. +- name: This command will change the working directory to somedir/ and will only run when somedir/somelog.txt doesn't exist. + shell: somescript.sh >> somelog.txt args: chdir: somedir/ creates: somelog.txt -# Run a command that uses non-posix shell-isms (in this example /bin/sh -# doesn't handle redirection and wildcards together but bash does) -- shell: cat < /tmp/*txt +- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but bash does) + shell: cat < /tmp/*txt args: executable: /bin/bash + +- name: Run a command using a templated variable (always use quote filter to avoid injection) + shell: cat {{ myfile|quote }} ''' RETURN = '''