mirror of
https://github.com/ansible/awx.git
synced 2026-01-10 15:32:07 -03:30
remove the usage of create_temporary_fifo from credential plugins
this resolves an issue that causes an endless hang on with Cyberark AIM lookups when a certificate *and* key are specified the underlying issue here is that we can't rely on the underyling Python ssl implementation to *only* read from the fifo that stores the pem data *only once*; in reality, we need to just use *actual* tempfiles for stability purposes see: https://github.com/ansible/awx/issues/6986 see: https://github.com/urllib3/urllib3/issues/1880
This commit is contained in:
parent
f4dfbcdf18
commit
01c89398b7
@ -7,6 +7,7 @@ This is a list of high-level changes for each release of AWX. A full list of com
|
||||
- Removed support for HipChat notifications ([EoL announcement](https://www.atlassian.com/partnerships/slack/faq#faq-98b17ca3-247f-423b-9a78-70a91681eff0)); all previously-created HipChat notification templates will be deleted due to this removal.
|
||||
- Fixed a bug which broke AWX installations with oc version 4.3 (https://github.com/ansible/awx/pull/6948/files)
|
||||
- Fixed a performance issue that caused notable delay of stdout processing for playbooks run against large numbers of hosts (https://github.com/ansible/awx/issues/6991)
|
||||
- Fixed a bug that caused CyberArk AIM credential plugin looks to hang forever in some environments (https://github.com/ansible/awx/issues/6986)
|
||||
- Fixed a bug that caused ANY/ALL converage settings not to properly save when editing approval nodes in the UI (https://github.com/ansible/awx/issues/6998)
|
||||
- Fixed a bug that broke support for the satellite6_group_prefix source variable (https://github.com/ansible/awx/issues/7031)
|
||||
- Fixed a bug in awx-manage run_wsbroadcast --status in kubernetes (https://github.com/ansible/awx/pull/7009)
|
||||
|
||||
@ -1,15 +1,10 @@
|
||||
from .plugin import CredentialPlugin
|
||||
from .plugin import CredentialPlugin, CertFiles
|
||||
|
||||
from urllib.parse import quote, urlencode, urljoin
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import requests
|
||||
|
||||
# AWX
|
||||
from awx.main.utils import (
|
||||
create_temporary_fifo,
|
||||
)
|
||||
|
||||
aim_inputs = {
|
||||
'fields': [{
|
||||
'id': 'url',
|
||||
@ -81,21 +76,13 @@ def aim_backend(**kwargs):
|
||||
request_qs = '?' + urlencode(query_params, quote_via=quote)
|
||||
request_url = urljoin(url, '/'.join(['AIMWebService', 'api', 'Accounts']))
|
||||
|
||||
cert = None
|
||||
if client_cert and client_key:
|
||||
cert = (
|
||||
create_temporary_fifo(client_cert.encode()),
|
||||
create_temporary_fifo(client_key.encode())
|
||||
with CertFiles(client_cert, client_key) as cert:
|
||||
res = requests.get(
|
||||
request_url + request_qs,
|
||||
timeout=30,
|
||||
cert=cert,
|
||||
verify=verify,
|
||||
)
|
||||
elif client_cert:
|
||||
cert = create_temporary_fifo(client_cert.encode())
|
||||
|
||||
res = requests.get(
|
||||
request_url + request_qs,
|
||||
timeout=30,
|
||||
cert=cert,
|
||||
verify=verify,
|
||||
)
|
||||
res.raise_for_status()
|
||||
return res.json()['Content']
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from .plugin import CredentialPlugin
|
||||
from .plugin import CredentialPlugin, CertFiles
|
||||
|
||||
import base64
|
||||
from urllib.parse import urljoin, quote_plus
|
||||
@ -6,11 +6,6 @@ from urllib.parse import urljoin, quote_plus
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import requests
|
||||
|
||||
# AWX
|
||||
from awx.main.utils import (
|
||||
create_temporary_fifo,
|
||||
)
|
||||
|
||||
|
||||
conjur_inputs = {
|
||||
'fields': [{
|
||||
@ -65,22 +60,20 @@ def conjur_backend(**kwargs):
|
||||
'headers': {'Content-Type': 'text/plain'},
|
||||
'data': api_key
|
||||
}
|
||||
if cacert:
|
||||
auth_kwargs['verify'] = create_temporary_fifo(cacert.encode())
|
||||
|
||||
# https://www.conjur.org/api.html#authentication-authenticate-post
|
||||
resp = requests.post(
|
||||
urljoin(url, '/'.join(['authn', account, username, 'authenticate'])),
|
||||
**auth_kwargs
|
||||
)
|
||||
with CertFiles(cacert) as cert:
|
||||
# https://www.conjur.org/api.html#authentication-authenticate-post
|
||||
auth_kwargs['verify'] = cert
|
||||
resp = requests.post(
|
||||
urljoin(url, '/'.join(['authn', account, username, 'authenticate'])),
|
||||
**auth_kwargs
|
||||
)
|
||||
resp.raise_for_status()
|
||||
token = base64.b64encode(resp.content).decode('utf-8')
|
||||
|
||||
lookup_kwargs = {
|
||||
'headers': {'Authorization': 'Token token="{}"'.format(token)},
|
||||
}
|
||||
if cacert:
|
||||
lookup_kwargs['verify'] = create_temporary_fifo(cacert.encode())
|
||||
|
||||
# https://www.conjur.org/api.html#secrets-retrieve-a-secret-get
|
||||
path = urljoin(url, '/'.join([
|
||||
@ -92,7 +85,9 @@ def conjur_backend(**kwargs):
|
||||
if version:
|
||||
path = '?'.join([path, version])
|
||||
|
||||
resp = requests.get(path, timeout=30, **lookup_kwargs)
|
||||
with CertFiles(cacert) as cert:
|
||||
lookup_kwargs['verify'] = cert
|
||||
resp = requests.get(path, timeout=30, **lookup_kwargs)
|
||||
resp.raise_for_status()
|
||||
return resp.text
|
||||
|
||||
|
||||
@ -3,16 +3,11 @@ import os
|
||||
import pathlib
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from .plugin import CredentialPlugin
|
||||
from .plugin import CredentialPlugin, CertFiles
|
||||
|
||||
import requests
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# AWX
|
||||
from awx.main.utils import (
|
||||
create_temporary_fifo,
|
||||
)
|
||||
|
||||
base_inputs = {
|
||||
'fields': [{
|
||||
'id': 'url',
|
||||
@ -129,14 +124,13 @@ def approle_auth(**kwargs):
|
||||
cacert = kwargs.get('cacert', None)
|
||||
|
||||
request_kwargs = {'timeout': 30}
|
||||
if cacert:
|
||||
request_kwargs['verify'] = create_temporary_fifo(cacert.encode())
|
||||
|
||||
# AppRole Login
|
||||
request_kwargs['json'] = {'role_id': role_id, 'secret_id': secret_id}
|
||||
sess = requests.Session()
|
||||
request_url = '/'.join([url, 'auth', auth_path, 'login']).rstrip('/')
|
||||
resp = sess.post(request_url, **request_kwargs)
|
||||
with CertFiles(cacert) as cert:
|
||||
request_kwargs['verify'] = cert
|
||||
resp = sess.post(request_url, **request_kwargs)
|
||||
resp.raise_for_status()
|
||||
token = resp.json()['auth']['client_token']
|
||||
return token
|
||||
@ -152,8 +146,6 @@ def kv_backend(**kwargs):
|
||||
api_version = kwargs['api_version']
|
||||
|
||||
request_kwargs = {'timeout': 30}
|
||||
if cacert:
|
||||
request_kwargs['verify'] = create_temporary_fifo(cacert.encode())
|
||||
|
||||
sess = requests.Session()
|
||||
sess.headers['Authorization'] = 'Bearer {}'.format(token)
|
||||
@ -180,7 +172,9 @@ def kv_backend(**kwargs):
|
||||
path_segments = [secret_path]
|
||||
|
||||
request_url = urljoin(url, '/'.join(['v1'] + path_segments)).rstrip('/')
|
||||
response = sess.get(request_url, **request_kwargs)
|
||||
with CertFiles(cacert) as cert:
|
||||
request_kwargs['verify'] = cert
|
||||
response = sess.get(request_url, **request_kwargs)
|
||||
response.raise_for_status()
|
||||
|
||||
json = response.json()
|
||||
@ -205,8 +199,6 @@ def ssh_backend(**kwargs):
|
||||
cacert = kwargs.get('cacert', None)
|
||||
|
||||
request_kwargs = {'timeout': 30}
|
||||
if cacert:
|
||||
request_kwargs['verify'] = create_temporary_fifo(cacert.encode())
|
||||
|
||||
request_kwargs['json'] = {'public_key': kwargs['public_key']}
|
||||
if kwargs.get('valid_principals'):
|
||||
@ -218,7 +210,10 @@ def ssh_backend(**kwargs):
|
||||
sess.headers['X-Vault-Token'] = token
|
||||
# https://www.vaultproject.io/api/secret/ssh/index.html#sign-ssh-key
|
||||
request_url = '/'.join([url, secret_path, 'sign', role]).rstrip('/')
|
||||
resp = sess.post(request_url, **request_kwargs)
|
||||
|
||||
with CertFiles(cacert) as cert:
|
||||
request_kwargs['verify'] = cert
|
||||
resp = sess.post(request_url, **request_kwargs)
|
||||
|
||||
resp.raise_for_status()
|
||||
return resp.json()['data']['signed_key']
|
||||
|
||||
@ -1,3 +1,45 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
CredentialPlugin = namedtuple('CredentialPlugin', ['name', 'inputs', 'backend'])
|
||||
|
||||
|
||||
class CertFiles():
|
||||
"""
|
||||
A context manager used for writing a certificate and (optional) key
|
||||
to $TMPDIR, and cleaning up afterwards.
|
||||
|
||||
This is particularly useful as a shared resource for credential plugins
|
||||
that want to pull cert/key data out of the database and persist it
|
||||
temporarily to the file system so that it can loaded into the openssl
|
||||
certificate chain (generally, for HTTPS requests plugins make via the
|
||||
Python requests library)
|
||||
|
||||
with CertFiles(cert_data, key_data) as cert:
|
||||
# cert is string representing a path to the cert or pemfile
|
||||
# temporarily written to disk
|
||||
requests.post(..., cert=cert)
|
||||
"""
|
||||
|
||||
certfile = None
|
||||
|
||||
def __init__(self, cert, key=None):
|
||||
self.cert = cert
|
||||
self.key = key
|
||||
|
||||
def __enter__(self):
|
||||
if not self.cert:
|
||||
return None
|
||||
self.certfile = tempfile.NamedTemporaryFile('wb', delete=False)
|
||||
self.certfile.write(self.cert.encode())
|
||||
if self.key:
|
||||
self.certfile.write(b'\n')
|
||||
self.certfile.write(self.key.encode())
|
||||
self.certfile.flush()
|
||||
return str(self.certfile.name)
|
||||
|
||||
def __exit__(self, *args):
|
||||
if self.certfile and os.path.exists(self.certfile.name):
|
||||
os.remove(self.certfile.name)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user