Repository: ansible/ansible

Issue:
Vault encrypted files should not show YAML formatting errors if any
Ansible outputs debugging information when a YAML file has parsing errors. This is useful, however it shouldn't output my encrypted secrets. In this case a line number should be enough.



Discussion:
Thanks for filing a ticket! I am the friendly GitHub Ansibot. I see you did not fill out your issue description based on our new issue template. Please copy the contents of this [template](https://raw2.github.com/ansible/ansible/devel/examples/issues/ISSUE_TEMPLATE.md) and **paste it into the description** of your ticket. 

Our system will automatically close tickets that do not have an issue template filled out within 7 days. Please note that due to large interest in Ansible, humans may not comment on your ticket if you ask them questions. Don't worry, you're still in the queue and the robots are looking after you.

So that's an interesting request and I'll consider whether we can do something here.

However as you've already provided decryption credentials to unlock the file, and it's informing you about problems in the output that would be made available later to the program.   Basically you did this as you, and it needs to tell you what the problem is in order for it to be fixed.  Throwing away this data would make things harder -- yes, there's going to be output on your terminal, but there's also output while you are using "ansible-vault edit" on the same file.

Also if you say, encrypted an Apache port, and accidentally send the port number to the "enabled=" parameter of a service module (yes, this is silly) like so:

   enabled={{ apache_port_number }}

Then yes, the system is going to tell you that enabled doesn't accept a value of 8080.

The taintedness of already-decrypted variables is not going to be tracked throughout the system, in this case, what you have is a successfully decrypted data at this point, and for those reading the ticket, there's no exposure of the variable as you still need to provide proper passwords to decrypt to get this far.

I'd like to know more about your use case here if you can provide it.

Are you using Jenkins, how are you sharing things with your team, etc?

You could add a command line argument (`--debug-vaults`) to allow debugging output for encrypted vaults, disabling it by default. It was quite a big surprise to see those passwords scrolling by, very unexpected.

We're deploying from the command line, not doing continuos deployment. The vaults are checked in to source control. Trusted team members get the password for the encrypted vault so they can deploy to staging and/or production; others can only set up development VMs.

In your scenario, the trusted team members have access to the vault password -- curious if you can elaborate who has access to see the output of the program?

Is this perhaps more of a looking-over-the-shoulder scenario?

Understanding the use cases is very helpful, so this is much appreciated.

Thank you!

Yeah, looking over the shoulders is one issue (think of deploying from a plane, "ah, so that's your stripe private key")—but also other scenarios are problematic, like logging the output somewhere and not knowing that secrets could be exposed accidentally. 

Yeah part of what I was getting at is some degree of logging, such as module parameters -- is not going to be 100% covered and that should be apparent up front.  (Which I think is not so much a vulnerability but something we should just make note of in the documentation -- be aware-- the variables you set will be made available to the program and the remote nodes, naturally, so...).

Though I can also see someone committing an invalid YAML in valid, having the vault key on the Jenkins box, and the logging being made a bit too permissively available.

Thanks for info, understand much better now, we'll see what we can add.


Resolving patch:
diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py
--- a/lib/ansible/utils/__init__.py
+++ b/lib/ansible/utils/__init__.py
@@ -464,32 +464,33 @@ def process_common_errors(msg, probline, column):
 
     return msg
 
-def process_yaml_error(exc, data, path=None):
+def process_yaml_error(exc, data, path=None, show_content=True):
     if hasattr(exc, 'problem_mark'):
         mark = exc.problem_mark
-        if mark.line -1 >= 0:
-            before_probline = data.split("\n")[mark.line-1]
-        else:
-            before_probline = ''
-        probline = data.split("\n")[mark.line]
-        arrow = " " * mark.column + "^"
-        msg = """Syntax Error while loading YAML script, %s
+        if show_content:
+            if mark.line -1 >= 0:
+                before_probline = data.split("\n")[mark.line-1]
+            else:
+                before_probline = ''
+            probline = data.split("\n")[mark.line]
+            arrow = " " * mark.column + "^"
+            msg = """Syntax Error while loading YAML script, %s
 Note: The error may actually appear before this position: line %s, column %s
 
 %s
 %s
 %s""" % (path, mark.line + 1, mark.column + 1, before_probline, probline, arrow)
 
-        unquoted_var = None
-        if '{{' in probline and '}}' in probline:
-            if '"{{' not in probline or "'{{" not in probline:
-                unquoted_var = True
+            unquoted_var = None
+            if '{{' in probline and '}}' in probline:
+                if '"{{' not in probline or "'{{" not in probline:
+                    unquoted_var = True
 
-        msg = process_common_errors(msg, probline, mark.column)
-        if not unquoted_var:
             msg = process_common_errors(msg, probline, mark.column)
-        else:
-            msg = msg + """
+            if not unquoted_var:
+                msg = process_common_errors(msg, probline, mark.column)
+            else:
+                msg = msg + """
 We could be wrong, but this one looks like it might be an issue with
 missing quotes.  Always quote template expression brackets when they 
 start a value. For instance:            
@@ -503,7 +504,15 @@ def process_yaml_error(exc, data, path=None):
       - "{{ foo }}"      
 
 """
-            msg = process_common_errors(msg, probline, mark.column)
+                msg = process_common_errors(msg, probline, mark.column)
+        else:
+            # most likely displaying a file with sensitive content,
+            # so don't show any of the actual lines of yaml just the
+            # line number itself
+            msg = """Syntax error while loading YAML script, %s
+The error appears to have been on line %s, column %s, but may actually
+be before there depending on the exact syntax problem.
+""" % (path, mark.line + 1, mark.column + 1)
 
     else:
         # No problem markers means we have to throw a generic
@@ -519,6 +528,7 @@ def parse_yaml_from_file(path, vault_password=None):
     ''' convert a yaml file to a data structure '''
 
     data = None
+    show_content = True
 
     try:
         data = open(path).read()
@@ -528,11 +538,12 @@ def parse_yaml_from_file(path, vault_password=None):
     vault = VaultLib(password=vault_password)
     if vault.is_encrypted(data):
         data = vault.decrypt(data)
+        show_content = False
 
     try:
         return parse_yaml(data, path_hint=path)
     except yaml.YAMLError, exc:
-        process_yaml_error(exc, data, path)
+        process_yaml_error(exc, data, path, show_content)
 
 def parse_kv(args):
     ''' convert a string of key/value items to a dict '''


Test patch: