14

Sometimes I would like to use Ansible's lineinfile or blockinfile modules to write a password into some configuration file. If I do so, the whole line or block, password included, ends up in my syslog.

As I don't consider syslog to be a secure place to have my passwords stored in, how can I tell Ansible not to leak my password into syslog? I hope there is a way to do this, otherwise I would consider this to be a big security problem in Ansible.

You can reproduce it for example with this ad-hoc command:

ansible localhost -m blockinfile -a 'dest=/tmp/ansible_password_leak create=yes block="Password = {{password}}"' -e 'password=secret'

Here is what ends up in syslog:

ansible-blockinfile: Invoked with directory_mode=None force=None remote_src=None insertafter=None owner=None follow=False marker=# {mark} ANSIBLE MANAGED BLOCK group=None insertbefore=None create=True setype=None content=None serole=None state=present dest=/tmp/ansible_password_leak selevel=None regexp=None validate=None src=None seuser=None delimiter=None mode=None backup=False block=Password = secret

For the example I used Ansible 2.0.0.2 from the official Ansible Ubuntu PPA on a Debian "Jessie" 8 system.

4 Answers 4

6

The no_log attribute hides data in syslog. It can be applied to a single task

- name: secret task
  shell: /usr/bin/do_something --value={{ secret_value }}
  no_log: True

or the playbook:

- hosts: all
  no_log: True

Debugging is not really possible when activated so it is recommended to use it only for single tasks. This feature is available since version 1.5 of Ansible. As stated in the release announcement for the 1.5 release:

Tasks also can now take a "no_log=True" option to prevent sensitive tasks from hitting syslog. (Parameters that looked like passwords were already filtered)

passwords should be filtered in most cases.

4
  • This effectively hides the passwords from syslog but it disables the logging output in the console output at the same time. Is there any way to change that?
    – aef
    Feb 9, 2016 at 9:46
  • I'm sorry. I found little information on this topic. I would suggest to set the attribute only for tasks and only once you debugged your play. As cited Ansible should already filter parameters that look like passwords. So maybe it is a bug. Again I don't know how Ansible determines if a parameter is a password. Maybe it is a bug / missing feature to hide password = XXX. Feb 9, 2016 at 9:53
  • Where did you get the impression that passwords are supposed to be hidden by default in Ansible? Is this mentioned somewhere in the documentation?
    – aef
    Feb 9, 2016 at 12:15
  • Last quote in my answer (Parameters that looked like passwords were already filtered). But I haven't found any other source for that functionality Feb 9, 2016 at 12:26
4

I developped a callback plugin to hide passwords for default outputs, it parse ouput dictionary for key that contains password, for each of them, it replace value by ********.

Create a file named protect_data.py in folder ./plugins/callback add add this code :

from ansible.plugins.callback.default import CallbackModule as CallbackModule_default
import os, collections

class CallbackModule(CallbackModule_default):
    CALLBACK_VERSION = 2.0
    CALLBACK_TYPE = 'stdout'
    CALLBACK_NAME = 'protect_data'

    def __init__(self, display=None):
        super(CallbackModule, self).__init__(display)

    def hide_password(self, result):
        ret = {}
        for key, value in result.iteritems():
            if isinstance(value, collections.Mapping):
                ret[key] = self.hide_password(value)
            else:
                if "password" in key:
                    ret[key] = "********"
                else:
                    ret[key] = value
        return ret

    def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False):
        return super(CallbackModule, self)._dump_results(self.hide_password(result), indent, sort_keys, keep_invocation)

In file ansible.cfg:

  • uncomment line with stdout_callback and set this plugin name a value (stdout_callback=protect_data)
  • uncomment line with callback_plugins and set value ./plugins/callback

Output is only modified for this plugin, if you use another plugin to display output (logentries, ...), you have to do the same with it

5
  • Oh, wow, that's brilliant. However, this requires me to set a dict with key name 'password' for everything that contains a secret. I would have loved a meta flag to indicate a variable contains a secret instead, but thanks! Other Q: does this also mask the secrets in output with ansible-playbook --diff (file diff changes)?
    – gertvdijk
    Jul 5, 2018 at 8:32
  • I don't know, I never tried
    – Nelson G.
    Jul 6, 2018 at 8:57
  • Hi @NelsonG, I see this was answered in 2016.. I'm trying get this working but failing with error ERROR! Unexpected Exception, this is probably a bug: __init__() takes exactly 1 argument (2 given). Just to be sure I used python2.7.5 but doesn't seem to be working.
    – harshavmb
    Nov 9, 2023 at 9:24
  • so I got it working by removing display argument & here is the corrected snippet for python2.x versions def __init__(self, display=None): super(CallbackModule, self).__init__()
    – harshavmb
    Nov 9, 2023 at 10:29
  • Maybe you're using a more recent version of Ansible. For example, version 2.16 don't need display arguments (github.com/ansible/ansible/blob/v2.16.0/lib/ansible/plugins/…). When I wrote this callback, if I remember correcly, I was using ansible version 2.1.6, and display argument exists in this version (github.com/ansible/ansible/blob/v2.1.6.0-1/lib/ansible/plugins/…)
    – Nelson G.
    Nov 10, 2023 at 9:12
0

The workaround I've arrived at is:

- name: something that would ordinarily log a password
  something.that.requires:
    secret: "{{ a_secret }}"
  no_log: true # avoid logging the secret
  register: the_output_so_we_can_debug_if_it_fails
- name: Log the output of something that would ordinarily log a password with the password redacted
  ansible.builtin.debug:
    msg: "{{ (the_output_so_we_can_debug_if_it_fails ~ '') | replace(a_secret, 'a_secret') }}"
-3

One might suggest that using Vault instead would obviate the problem.

5
  • This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
    – chicks
    Feb 16, 2018 at 2:58
  • 2
    Vault helps to encrypt data at rest, but when passwords are in use, they can easily appear in log files. Feb 16, 2018 at 6:38
  • @chicks This looks like a wrong answer, not a non-answer. Feb 16, 2018 at 20:07
  • I did not see that option in the review tools. Since this is more like a comment than an answer I feel like I handled this reasonably.
    – chicks
    Feb 16, 2018 at 20:15
  • My flag was also declined, and I still do not see how the above sentence is an answer about how to reduce Ansible verbosity. It is at most a comment suggesting another idea, certainly not an answer to the question. Feb 21, 2018 at 1:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .