Use TLS on revocation notification webhook
- Include system installed CA certificates when verifying webhook server certificate - Include the CA certificates added via configuration file option 'trusted_server_ca' Resolves: RHEL-78057 Resolves: RHEL-78313 Resolves: RHEL-78316 Signed-off-by: Sergio Correia <scorreia@redhat.com>
This commit is contained in:
parent
8d907c5ddf
commit
5d41ae0699
167
0016-Use-TLS-on-revocation-notification-webhook.patch
Normal file
167
0016-Use-TLS-on-revocation-notification-webhook.patch
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
From 4bd644b74719fdbb6c521d3d5eb2430d8dc18b36 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Correia <scorreia@redhat.com>
|
||||||
|
Date: Wed, 5 Feb 2025 16:16:25 +0000
|
||||||
|
Subject: [PATCH 16/16] Use TLS on revocation notification webhook
|
||||||
|
|
||||||
|
---
|
||||||
|
keylime/requests_client.py | 5 ++
|
||||||
|
keylime/revocation_notifier.py | 91 +++++++++++++++++++++++-----------
|
||||||
|
2 files changed, 68 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/keylime/requests_client.py b/keylime/requests_client.py
|
||||||
|
index 85a175c..e993fbc 100644
|
||||||
|
--- a/keylime/requests_client.py
|
||||||
|
+++ b/keylime/requests_client.py
|
||||||
|
@@ -1,3 +1,4 @@
|
||||||
|
+import re
|
||||||
|
import ssl
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
@@ -15,6 +16,10 @@ class RequestsClient:
|
||||||
|
ignore_hostname: bool = True,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> None:
|
||||||
|
+ # Remove eventual "http?://" from the base url
|
||||||
|
+ if base_url.startswith("http"):
|
||||||
|
+ base_url = re.sub(r"https?://", "", base_url)
|
||||||
|
+
|
||||||
|
if tls_enabled:
|
||||||
|
self.base_url = f"https://{base_url}"
|
||||||
|
else:
|
||||||
|
diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py
|
||||||
|
index 5cc8b1a..434bf64 100644
|
||||||
|
--- a/keylime/revocation_notifier.py
|
||||||
|
+++ b/keylime/revocation_notifier.py
|
||||||
|
@@ -9,8 +9,9 @@ from typing import Any, Callable, Dict, Optional, Set
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
-from keylime import config, crypto, json, keylime_logging
|
||||||
|
+from keylime import config, crypto, json, keylime_logging, web_util
|
||||||
|
from keylime.common import retry
|
||||||
|
+from keylime.requests_client import RequestsClient
|
||||||
|
|
||||||
|
logger = keylime_logging.init_logging("revocation_notifier")
|
||||||
|
broker_proc: Optional[Process] = None
|
||||||
|
@@ -109,7 +110,10 @@ def notify(tosend: Dict[str, Any]) -> None:
|
||||||
|
exponential_backoff = config.getboolean("verifier", "exponential_backoff")
|
||||||
|
next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||||
|
logger.debug(
|
||||||
|
- "Unable to publish revocation message %d times, trying again in %f seconds: %s", i, next_retry, e
|
||||||
|
+ "Unable to publish revocation message %d times, trying again in %f seconds: %s",
|
||||||
|
+ i,
|
||||||
|
+ next_retry,
|
||||||
|
+ e,
|
||||||
|
)
|
||||||
|
time.sleep(next_retry)
|
||||||
|
mysock.close()
|
||||||
|
@@ -132,30 +136,50 @@ def notify_webhook(tosend: Dict[str, Any]) -> None:
|
||||||
|
def worker_webhook(tosend: Dict[str, Any], url: str) -> None:
|
||||||
|
interval = config.getfloat("verifier", "retry_interval")
|
||||||
|
exponential_backoff = config.getboolean("verifier", "exponential_backoff")
|
||||||
|
- with requests.Session() as session:
|
||||||
|
- logger.info("Sending revocation event via webhook...")
|
||||||
|
- for i in range(config.getint("verifier", "max_retries")):
|
||||||
|
- next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||||
|
+
|
||||||
|
+ max_retries = config.getint("verifier", "max_retries")
|
||||||
|
+ if max_retries <= 0:
|
||||||
|
+ logger.info("Invalid value found in 'max_retries' option for verifier, using default value")
|
||||||
|
+ max_retries = 5
|
||||||
|
+
|
||||||
|
+ # Get TLS options from the configuration
|
||||||
|
+ (cert, key, trusted_ca, key_password), verify_server_cert = web_util.get_tls_options(
|
||||||
|
+ "verifier", is_client=True, logger=logger
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ # Generate the TLS context using the obtained options
|
||||||
|
+ tls_context = web_util.generate_tls_context(cert, key, trusted_ca, key_password, is_client=True, logger=logger)
|
||||||
|
+
|
||||||
|
+ logger.info("Sending revocation event via webhook to %s ...", url)
|
||||||
|
+ for i in range(max_retries):
|
||||||
|
+ next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||||
|
+
|
||||||
|
+ with RequestsClient(
|
||||||
|
+ url,
|
||||||
|
+ verify_server_cert,
|
||||||
|
+ tls_context,
|
||||||
|
+ ) as client:
|
||||||
|
try:
|
||||||
|
- response = session.post(url, json=tosend, timeout=5)
|
||||||
|
- if response.status_code in [200, 202]:
|
||||||
|
- break
|
||||||
|
-
|
||||||
|
- logger.debug(
|
||||||
|
- "Unable to publish revocation message %d times via webhook, "
|
||||||
|
- "trying again in %d seconds. "
|
||||||
|
- "Server returned status code: %s",
|
||||||
|
- i,
|
||||||
|
- next_retry,
|
||||||
|
- response.status_code,
|
||||||
|
- )
|
||||||
|
- except requests.exceptions.RequestException as e:
|
||||||
|
- logger.debug(
|
||||||
|
- "Unable to publish revocation message %d times via webhook, trying again in %d seconds: %s",
|
||||||
|
- i,
|
||||||
|
- next_retry,
|
||||||
|
- e,
|
||||||
|
- )
|
||||||
|
+ res = client.post("", json=tosend, timeout=5)
|
||||||
|
+ except requests.exceptions.SSLError as ssl_error:
|
||||||
|
+ if "TLSV1_ALERT_UNKNOWN_CA" in str(ssl_error):
|
||||||
|
+ logger.warning(
|
||||||
|
+ "Keylime does not recognize certificate from peer. Check if verifier 'trusted_server_ca' is configured correctly"
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ raise ssl_error from ssl_error
|
||||||
|
+
|
||||||
|
+ if res and res.status_code in [200, 202]:
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ logger.debug(
|
||||||
|
+ "Unable to publish revocation message %d times via webhook, "
|
||||||
|
+ "trying again in %d seconds. "
|
||||||
|
+ "Server returned status code: %s",
|
||||||
|
+ i + 1,
|
||||||
|
+ next_retry,
|
||||||
|
+ res.status_code,
|
||||||
|
+ )
|
||||||
|
|
||||||
|
time.sleep(next_retry)
|
||||||
|
|
||||||
|
@@ -167,7 +191,11 @@ def notify_webhook(tosend: Dict[str, Any]) -> None:
|
||||||
|
cert_key = None
|
||||||
|
|
||||||
|
|
||||||
|
-def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str, Any]], None], cert_path: str) -> None:
|
||||||
|
+def process_revocation(
|
||||||
|
+ revocation: Dict[str, Any],
|
||||||
|
+ callback: Callable[[Dict[str, Any]], None],
|
||||||
|
+ cert_path: str,
|
||||||
|
+) -> None:
|
||||||
|
global cert_key
|
||||||
|
|
||||||
|
if cert_key is None:
|
||||||
|
@@ -179,10 +207,17 @@ def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str,
|
||||||
|
cert_key = crypto.x509_import_pubkey(certpem)
|
||||||
|
|
||||||
|
if cert_key is None:
|
||||||
|
- logger.warning("Unable to check signature of revocation message: %s not available", cert_path)
|
||||||
|
+ logger.warning(
|
||||||
|
+ "Unable to check signature of revocation message: %s not available",
|
||||||
|
+ cert_path,
|
||||||
|
+ )
|
||||||
|
elif "signature" not in revocation or revocation["signature"] == "none":
|
||||||
|
logger.warning("No signature on revocation message from server")
|
||||||
|
- elif not crypto.rsa_verify(cert_key, revocation["msg"].encode("utf-8"), revocation["signature"].encode("utf-8")):
|
||||||
|
+ elif not crypto.rsa_verify(
|
||||||
|
+ cert_key,
|
||||||
|
+ revocation["msg"].encode("utf-8"),
|
||||||
|
+ revocation["signature"].encode("utf-8"),
|
||||||
|
+ ):
|
||||||
|
logger.error("Invalid revocation message siganture %s", revocation)
|
||||||
|
else:
|
||||||
|
message = json.loads(revocation["msg"])
|
||||||
|
--
|
||||||
|
2.47.1
|
||||||
|
|
13
keylime.spec
13
keylime.spec
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
Name: keylime
|
Name: keylime
|
||||||
Version: 7.3.0
|
Version: 7.3.0
|
||||||
Release: 14%{?dist}
|
Release: 15%{?dist}
|
||||||
Summary: Open source TPM software for Bootstrapping and Maintaining Trust
|
Summary: Open source TPM software for Bootstrapping and Maintaining Trust
|
||||||
|
|
||||||
URL: https://github.com/keylime/keylime
|
URL: https://github.com/keylime/keylime
|
||||||
@ -32,6 +32,7 @@ Patch: 0012-Restore-create-allowlist.patch
|
|||||||
Patch: 0013-Set-generator-and-timestamp-in-create-policy.patch
|
Patch: 0013-Set-generator-and-timestamp-in-create-policy.patch
|
||||||
Patch: 0014-tpm_util-Replace-a-logger.error-with-an-Exception-in.patch
|
Patch: 0014-tpm_util-Replace-a-logger.error-with-an-Exception-in.patch
|
||||||
Patch: 0015-Backport-keylime-policy-tool.patch
|
Patch: 0015-Backport-keylime-policy-tool.patch
|
||||||
|
Patch: 0016-Use-TLS-on-revocation-notification-webhook.patch
|
||||||
|
|
||||||
License: ASL 2.0 and MIT
|
License: ASL 2.0 and MIT
|
||||||
|
|
||||||
@ -374,6 +375,16 @@ fi
|
|||||||
%license LICENSE
|
%license LICENSE
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Feb 05 2025 Sergio Correia <scorreia@redhat.com> - 7.3.0-15
|
||||||
|
- Use TLS on revocation notification webhook
|
||||||
|
- Include system installed CA certificates when verifying webhook
|
||||||
|
server certificate
|
||||||
|
- Include the CA certificates added via configuration file option
|
||||||
|
'trusted_server_ca'
|
||||||
|
Resolves: RHEL-78057
|
||||||
|
Resolves: RHEL-78313
|
||||||
|
Resolves: RHEL-78316
|
||||||
|
|
||||||
* Fri Jan 10 2025 Sergio Correia <scorreia@redhat.com> - 7.3.0-14
|
* Fri Jan 10 2025 Sergio Correia <scorreia@redhat.com> - 7.3.0-14
|
||||||
- Backport keylime-policy tool
|
- Backport keylime-policy tool
|
||||||
Resolves: RHEL-75797
|
Resolves: RHEL-75797
|
||||||
|
Loading…
Reference in New Issue
Block a user