mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch 'webhook-configure-auth' into develop
This commit is contained in:
commit
b961aea447
2 changed files with 62 additions and 9 deletions
|
@ -54,6 +54,17 @@ A REST API for Salt
|
|||
will be sent in the clear!
|
||||
|
||||
.. versionadded:: 0.8.3
|
||||
webhook_disable_auth : False
|
||||
The :py:class:`Webhook` URL requires authentication by default but
|
||||
external services cannot always be configured to send authentication.
|
||||
See the Webhook documentation for suggestions on securing this
|
||||
interface.
|
||||
|
||||
.. versionadded:: 0.8.4.1
|
||||
webhook_url : /hook
|
||||
Configure the URL endpoint for the :py:class:`Webhook` entry point.
|
||||
|
||||
.. versionadded:: 0.8.4.1
|
||||
thread_pool : ``100``
|
||||
The number of worker threads to start up in the pool.
|
||||
|
||||
|
@ -1243,18 +1254,24 @@ class Webhook(object):
|
|||
A generic web hook entry point that fires an event on Salt's event bus
|
||||
|
||||
External services can POST data to this URL to trigger an event in Salt.
|
||||
For example, Jenkins-CI or Travis-CI, or GitHub web hooks.
|
||||
|
||||
This entry point does not require authentication. The event data is taken
|
||||
from the request body.
|
||||
For example, Amazon SNS, Jenkins-CI or Travis-CI, or GitHub web hooks.
|
||||
|
||||
.. note:: Be mindful of security
|
||||
|
||||
Salt's Reactor can run any code. If you write a Reactor SLS that
|
||||
responds to a hook event be sure to validate that the event came from a
|
||||
trusted source and contains valid data! Pass a secret key and use SSL.
|
||||
Salt's Reactor can run any code. A Reactor SLS that responds to a hook
|
||||
event is responsible for validating that the event came from a trusted
|
||||
source and contains valid data.
|
||||
|
||||
This is a generic interface and securing it is up to you!
|
||||
**This is a generic interface and securing it is up to you!**
|
||||
|
||||
This URL requires authentication however not all external services can
|
||||
be configured to authenticate. For this reason authentication can be
|
||||
selectively disabled for this URL. Follow best practices -- always use
|
||||
SSL, pass a secret key, configure the firewall to only allow traffic
|
||||
from a known source, etc.
|
||||
|
||||
The event data is taken from the request body. The
|
||||
:mailheader:`Content-Type` header is respected for the payload.
|
||||
|
||||
The event tag is prefixed with ``salt/netapi/hook`` and the URL path is
|
||||
appended to the end. For example, a ``POST`` request sent to
|
||||
|
@ -1280,6 +1297,9 @@ class Webhook(object):
|
|||
# Don't do any lowdata processing on the POST data
|
||||
'tools.lowdata_fmt.on': True,
|
||||
|
||||
# Auth can be overridden in __init__().
|
||||
'tools.salt_token.on': True,
|
||||
'tools.salt_auth.on': True,
|
||||
})
|
||||
|
||||
def __init__(self):
|
||||
|
@ -1287,6 +1307,10 @@ class Webhook(object):
|
|||
self.event = salt.utils.event.SaltEvent('master',
|
||||
self.opts.get('sock_dir', ''))
|
||||
|
||||
if cherrypy.config['apiopts'].get('webhook_disable_auth'):
|
||||
self._cp_config['tools.salt_token.on'] = False
|
||||
self._cp_config['tools.salt_auth.on'] = False
|
||||
|
||||
def POST(self, *args, **kwargs):
|
||||
'''
|
||||
Fire an event in Salt with a custom event tag and data
|
||||
|
@ -1422,7 +1446,6 @@ class API(object):
|
|||
'run': Run,
|
||||
'jobs': Jobs,
|
||||
'events': Events,
|
||||
'hook': Webhook,
|
||||
'stats': Stats,
|
||||
}
|
||||
|
||||
|
@ -1433,6 +1456,9 @@ class API(object):
|
|||
for url, cls in self.url_map.items():
|
||||
setattr(self, url, cls())
|
||||
|
||||
# Allow the Webhook URL to be overridden from the conf.
|
||||
setattr(self, self.apiopts.get('webhook_url', 'hook').lstrip('/'), Webhook())
|
||||
|
||||
if 'app' in self.apiopts:
|
||||
setattr(self, self.apiopts.get('app_path', 'app').lstrip('/'), App())
|
||||
|
||||
|
|
|
@ -30,6 +30,13 @@ class TestAuth(BaseRestCherryPyTest):
|
|||
request, response = self.request('/login')
|
||||
self.assertEqual(response.status, '200 OK')
|
||||
|
||||
def test_webhook_auth(self):
|
||||
'''
|
||||
Requests to the webhook URL require auth by default
|
||||
'''
|
||||
self.assertRaisesRegexp(cherrypy.InternalRedirect, '\/login',
|
||||
self.request, '/hook', method='POST', data={})
|
||||
|
||||
class TestLogin(BaseRestCherryPyTest):
|
||||
auth_creds = (
|
||||
('username', 'saltdev'),
|
||||
|
@ -69,3 +76,23 @@ class TestLogin(BaseRestCherryPyTest):
|
|||
'content-type': 'application/x-www-form-urlencoded'
|
||||
})
|
||||
self.assertEqual(response.status, '401 Unauthorized')
|
||||
|
||||
class TestWebhookDisableAuth(BaseRestCherryPyTest):
|
||||
__opts__ = {
|
||||
'rest_cherrypy': {
|
||||
'port': 8000,
|
||||
'debug': True,
|
||||
'webhook_disable_auth': True,
|
||||
},
|
||||
}
|
||||
|
||||
def test_webhook_noauth(self):
|
||||
'''
|
||||
Auth can be disabled for requests to the webhook URL
|
||||
'''
|
||||
body = urllib.urlencode({'foo': 'Foo!'})
|
||||
request, response = self.request('/hook', method='POST', body=body,
|
||||
headers={
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
})
|
||||
self.assertEqual(response.status, '200 OK')
|
||||
|
|
Loading…
Add table
Reference in a new issue