use a named pipe for isolated secret passthrough (not stdin)

it's not unusual for the secret data we pass into the `run_isolated.yml`
playbook to be quite long, namely because it can contain RSA key
data; by passing this value into the ansible-playbook process using
`vars_prompt`, we're limited by pexpect's tty line limit (which looks
like it caps out around 4k).  Because of this, large payloads are
being truncated and causing job run failures.

this changes the implementation to use a named pipe instead, which
doesn't have the same limitation

see: #7183
This commit is contained in:
Ryan Petrello
2017-07-20 12:21:42 -04:00
parent 1c5b0f023e
commit d42ea31f75
3 changed files with 14 additions and 10 deletions

View File

@@ -4,7 +4,6 @@ import codecs
import StringIO import StringIO
import json import json
import os import os
import re
import shutil import shutil
import stat import stat
import tempfile import tempfile
@@ -150,6 +149,13 @@ class IsolatedManager(object):
secrets['ssh_key_data'] = buff.getvalue() secrets['ssh_key_data'] = buff.getvalue()
os.remove(self.ssh_key_path) os.remove(self.ssh_key_path)
# write the entire secret payload to a named pipe
# the run_isolated.yml playbook will use a lookup to read this data
# into a variable, and will replicate the data into a named pipe on the
# isolated instance
secrets_path = os.path.join(self.private_data_dir, 'env')
run.open_fifo_write(secrets_path, base64.b64encode(json.dumps(secrets)))
self.build_isolated_job_data() self.build_isolated_job_data()
extra_vars = { extra_vars = {
@@ -172,9 +178,6 @@ class IsolatedManager(object):
logger.debug('Starting job on isolated host with `run_isolated.yml` playbook.') logger.debug('Starting job on isolated host with `run_isolated.yml` playbook.')
status, rc = IsolatedManager.run_pexpect( status, rc = IsolatedManager.run_pexpect(
args, self.awx_playbook_path(), self.management_env, buff, args, self.awx_playbook_path(), self.management_env, buff,
expect_passwords={
re.compile(r'Secret:\s*?$', re.M): base64.b64encode(json.dumps(secrets))
},
idle_timeout=self.idle_timeout, idle_timeout=self.idle_timeout,
job_timeout=settings.AWX_ISOLATED_LAUNCH_TIMEOUT, job_timeout=settings.AWX_ISOLATED_LAUNCH_TIMEOUT,
pexpect_timeout=5 pexpect_timeout=5
@@ -216,7 +219,9 @@ class IsolatedManager(object):
'- /project/.svn', '- /project/.svn',
'- /project/.hg', '- /project/.hg',
# don't rsync job events that are in the process of being written # don't rsync job events that are in the process of being written
'- /artifacts/job_events/*-partial.json.tmp' '- /artifacts/job_events/*-partial.json.tmp',
# rsync can't copy named pipe data - we're replicating this manually ourselves in the playbook
'- /env'
] ]
for filename, data in ( for filename, data in (

View File

@@ -163,7 +163,8 @@ def test_build_isolated_job_data(private_data_dir, rsa_key):
'- /project/.git', '- /project/.git',
'- /project/.svn', '- /project/.svn',
'- /project/.hg', '- /project/.hg',
'- /artifacts/job_events/*-partial.json.tmp' '- /artifacts/job_events/*-partial.json.tmp',
'- /env'
]) ])

View File

@@ -8,10 +8,8 @@
- name: Prepare data, dispatch job in isolated environment. - name: Prepare data, dispatch job in isolated environment.
hosts: all hosts: all
gather_facts: false gather_facts: false
vars_prompt: vars:
- prompt: "Secret" secret: "{{ lookup('pipe', 'cat ' + src + '/env') }}"
name: "secret"
private: yes
tasks: tasks: