Skip to content

Commit

Permalink
webhook: implement TLS client authentication
Browse files Browse the repository at this point in the history
Signed-off-by: László Várady <[email protected]>
  • Loading branch information
MrAnno committed Apr 30, 2024
1 parent e01ede7 commit 71d3e9a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
23 changes: 22 additions & 1 deletion syslog-ng/python-modules/webhook/scl/webhook.conf
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ block source webhook(
auth_token("")
tls_key_file("")
tls_cert_file("")

# for client authentication
tls_peer_verify(no)
tls_use_system_cert_store(no)
tls_ca_file("")
tls_ca_dir("")
...
)
{
Expand All @@ -35,6 +41,11 @@ block source webhook(
"auth_token" => "`auth_token`"
"tls_key_file" => "`tls_key_file`"
"tls_cert_file" => "`tls_cert_file`"

"tls_peer_verify" => `tls_peer_verify`
"tls_use_system_cert_store" => `tls_use_system_cert_store`
"tls_ca_file" => "`tls_ca_file`"
"tls_ca_dir" => "`tls_ca_dir`"
)
`__VARARGS__`
);
Expand All @@ -43,9 +54,15 @@ block source webhook(
block source webhook-json(
port("")
auth_token("")
prefix("")
tls_key_file("")
tls_cert_file("")
prefix("")

# for client authentication
tls_peer_verify(no)
tls_use_system_cert_store(no)
tls_ca_file("")
tls_ca_dir("")
...
)
{
Expand All @@ -54,6 +71,10 @@ block source webhook-json(
webhook(
port("`port`") auth_token("`auth_token`")
tls_key_file("`tls_key_file`") tls_cert_file("`tls_cert_file`")

tls_peer_verify(`tls_peer_verify`)
tls_use_system_cert_store(`tls_use_system_cert_store`)
tls_ca_file("`tls_ca_file`") tls_ca_dir("`tls_ca_dir`")
`__VARARGS__`
);
};
Expand Down
38 changes: 31 additions & 7 deletions syslog-ng/python-modules/webhook/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def get_current_user(self):

token = self.request.headers.get("Authorization", "").split(" ")
if len(token) != 2:
self.source.logger.debug("Auth failed, missing Authorization header or auth-scheme")
return False

token = token[1]
Expand All @@ -72,16 +73,14 @@ def init(self, options: dict[str, Any]) -> bool:
if not self.init_options(options):
return False

self.ssl_ctx = None
if self.tls_key_file:
self.ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self.ssl_ctx.load_cert_chain(self.tls_cert_file, self.tls_key_file)

if not self.port:
self.port = 443 if self.tls_key_file else 80

self.port = int(self.port)

self.ssl_ctx = None
if self.tls_key_file:
self.setup_tls()

self.suspended = threading.Event()
self.event_loop = asyncio.new_event_loop()
self.request_exit = asyncio.Event()
Expand Down Expand Up @@ -124,15 +123,40 @@ def request_exit(self) -> None :
asyncio.run_coroutine_threadsafe(self.stopServer(), self.event_loop)
pass

def log_access(self, req: tornado.web.RequestHandler):
def log_access(self, req: tornado.web.RequestHandler) -> None:
self.logger.debug(f"{req.get_status()} {req._request_summary()}")

def setup_tls(self) -> None:
self.ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self.ssl_ctx.load_cert_chain(certfile=self.tls_cert_file, keyfile=self.tls_key_file)

if self.tls_peer_verify:
self.logger.debug("Enabling client cert verification")
self.ssl_ctx.verify_mode = ssl.CERT_REQUIRED
else:
self.ssl_ctx.verify_mode = ssl.CERT_NONE

if self.tls_use_system_cert_store:
self.logger.debug("Using system cert store for client auth")
self.ssl_ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)

self.tls_ca_dir = self.tls_ca_dir if self.tls_ca_dir else None
self.tls_ca_file = self.tls_ca_file if self.tls_ca_file else None

if self.tls_ca_dir or self.tls_ca_file:
self.ssl_ctx.load_verify_locations(cafile=self.tls_ca_file, capath=self.tls_ca_dir)

def init_options(self, options: dict[str, Any]) -> bool:
try:
self.port = options.get("port")
self.auth_token = options.get("auth_token")
self.tls_key_file = options.get("tls_key_file")
self.tls_cert_file = options.get("tls_cert_file")

self.tls_peer_verify = bool(options.get("tls_peer_verify", False))
self.tls_use_system_cert_store = bool(options.get("tls_use_system_cert_store", False))
self.tls_ca_file = options.get("tls_ca_file")
self.tls_ca_dir = options.get("tls_ca_dir")
return True
except KeyError as e:
self.logger.error(f"Missing option '{e.args[0]}'")
Expand Down

0 comments on commit 71d3e9a

Please sign in to comment.