Add keylime to RHEL-9
Resolves: rhbz#2082989
This commit is contained in:
parent
9c72dfea97
commit
b19c921a82
1
.gitignore
vendored
1
.gitignore
vendored
@ -0,0 +1 @@
|
||||
/v6.4.1.tar.gz
|
@ -0,0 +1,39 @@
|
||||
From 90811cc0df4f32fbf9e5389cca15813e2f6395cb Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Correia <scorreia@redhat.com>
|
||||
Date: Fri, 3 Jun 2022 22:01:15 -0300
|
||||
Subject: [PATCH 1/5] Improve error handling when doing signature verification
|
||||
|
||||
This makes verify_signature_from_file() more consistent in that it will
|
||||
always raise an exception informing the signature verification failed,
|
||||
when this situation happens.
|
||||
|
||||
As it is, verify_signature() can raise a few different exceptions, and
|
||||
those were not handled by verify_signature_from_file().
|
||||
|
||||
Signed-off-by: Sergio Correia <scorreia@redhat.com>
|
||||
---
|
||||
keylime/signing.py | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/keylime/signing.py b/keylime/signing.py
|
||||
index 71f8be0..1353c1e 100644
|
||||
--- a/keylime/signing.py
|
||||
+++ b/keylime/signing.py
|
||||
@@ -30,7 +30,13 @@ def verify_signature_from_file(key_file, filename, sig_file, file_description):
|
||||
with open(filename, "rb") as file_f:
|
||||
file = file_f.read()
|
||||
|
||||
- if verify_signature(key, sig, file):
|
||||
+ verified = False
|
||||
+ try:
|
||||
+ verified = verify_signature(key, sig, file)
|
||||
+ except Exception as e:
|
||||
+ logger.warning("Unable to verify signature: %s", e)
|
||||
+
|
||||
+ if verified:
|
||||
logger.debug("%s passed signature verification", file_description.capitalize())
|
||||
else:
|
||||
raise Exception(
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,88 @@
|
||||
From 09db3fe88b22c0e1522343c14f184ea610883fcf Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Mon, 21 Mar 2022 11:06:45 +0100
|
||||
Subject: [PATCH 2/5] revocation_notifier: Factor out revocation message
|
||||
processing
|
||||
|
||||
This moves the revocation message processing logic out of
|
||||
await_notifications, so it can be called directly from the POST
|
||||
handler.
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
keylime/revocation_notifier.py | 45 ++++++++++++++++++----------------
|
||||
1 file changed, 24 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py
|
||||
index 4854a99..7cfe0e5 100644
|
||||
--- a/keylime/revocation_notifier.py
|
||||
+++ b/keylime/revocation_notifier.py
|
||||
@@ -165,6 +165,29 @@ def notify_webhook(tosend):
|
||||
cert_key = None
|
||||
|
||||
|
||||
+def process_revocation(revocation, callback, cert_path):
|
||||
+ global cert_key
|
||||
+
|
||||
+ if cert_key is None:
|
||||
+ # load up the CV signing public key
|
||||
+ if cert_path is not None and os.path.exists(cert_path):
|
||||
+ logger.info("Lazy loading the revocation certificate from %s", cert_path)
|
||||
+ with open(cert_path, "rb") as f:
|
||||
+ certpem = f.read()
|
||||
+ 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)
|
||||
+ 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")):
|
||||
+ logger.error("Invalid revocation message siganture %s", revocation)
|
||||
+ else:
|
||||
+ message = json.loads(revocation["msg"])
|
||||
+ logger.debug("Revocation signature validated for revocation: %s", message)
|
||||
+ callback(message)
|
||||
+
|
||||
+
|
||||
def await_notifications(callback, revocation_cert_path):
|
||||
# keep old typo "listen_notfications" around for a few versions
|
||||
assert config.getboolean("cloud_agent", "listen_notifications", fallback=False) or config.getboolean(
|
||||
@@ -175,8 +198,6 @@ def await_notifications(callback, revocation_cert_path):
|
||||
except ImportError as error:
|
||||
raise Exception("install PyZMQ for 'listen_notifications' option") from error
|
||||
|
||||
- global cert_key
|
||||
-
|
||||
if revocation_cert_path is None:
|
||||
raise Exception("must specify revocation_cert_path")
|
||||
|
||||
@@ -197,25 +218,7 @@ def await_notifications(callback, revocation_cert_path):
|
||||
while True:
|
||||
rawbody = mysock.recv()
|
||||
body = json.loads(rawbody)
|
||||
-
|
||||
- if cert_key is None:
|
||||
- # load up the CV signing public key
|
||||
- if revocation_cert_path is not None and os.path.exists(revocation_cert_path):
|
||||
- logger.info("Lazy loading the revocation certificate from %s", revocation_cert_path)
|
||||
- with open(revocation_cert_path, "rb") as f:
|
||||
- certpem = f.read()
|
||||
- cert_key = crypto.x509_import_pubkey(certpem)
|
||||
-
|
||||
- if cert_key is None:
|
||||
- logger.warning("Unable to check signature of revocation message: %s not available", revocation_cert_path)
|
||||
- elif "signature" not in body or body["signature"] == "none":
|
||||
- logger.warning("No signature on revocation message from server")
|
||||
- elif not crypto.rsa_verify(cert_key, body["msg"].encode("utf-8"), body["signature"].encode("utf-8")):
|
||||
- logger.error("Invalid revocation message siganture %s", body)
|
||||
- else:
|
||||
- message = json.loads(body["msg"])
|
||||
- logger.debug("Revocation signature validated for revocation: %s", message)
|
||||
- callback(message)
|
||||
+ process_revocation(body, callback, revocation_cert_path)
|
||||
|
||||
|
||||
def main():
|
||||
--
|
||||
2.35.1
|
||||
|
175
0003-keylime_agent-Support-notifications-revocation-REST-.patch
Normal file
175
0003-keylime_agent-Support-notifications-revocation-REST-.patch
Normal file
@ -0,0 +1,175 @@
|
||||
From 3defa4f6c399a4965dbea8b8188992bb470c2215 Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Mon, 21 Mar 2022 11:46:08 +0100
|
||||
Subject: [PATCH 3/5] keylime_agent: Support /notifications/revocation REST
|
||||
method
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
keylime/keylime_agent.py | 109 ++++++++++++++++++++++++---------------
|
||||
1 file changed, 68 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/keylime/keylime_agent.py b/keylime/keylime_agent.py
|
||||
index f8ea0f5..9ee9797 100644
|
||||
--- a/keylime/keylime_agent.py
|
||||
+++ b/keylime/keylime_agent.py
|
||||
@@ -210,17 +210,13 @@ class Handler(BaseHTTPRequestHandler):
|
||||
rest_params = web_util.get_restful_params(self.path)
|
||||
|
||||
if rest_params is None:
|
||||
- web_util.echo_json_response(self, 405, "Not Implemented: Use /keys/ interface")
|
||||
+ web_util.echo_json_response(self, 405, "Not Implemented: Use /keys/ or /notifications/ interface")
|
||||
return
|
||||
|
||||
if not rest_params["api_version"]:
|
||||
web_util.echo_json_response(self, 400, "API Version not supported")
|
||||
return
|
||||
|
||||
- if rest_params.get("keys", None) not in ["ukey", "vkey"]:
|
||||
- web_util.echo_json_response(self, 400, "Only /keys/ukey or /keys/vkey are supported")
|
||||
- return
|
||||
-
|
||||
content_length = int(self.headers.get("Content-Length", 0))
|
||||
if content_length <= 0:
|
||||
logger.warning("POST returning 400 response, expected content in message. url: %s", self.path)
|
||||
@@ -230,6 +226,26 @@ class Handler(BaseHTTPRequestHandler):
|
||||
post_body = self.rfile.read(content_length)
|
||||
try:
|
||||
json_body = json.loads(post_body)
|
||||
+ except Exception as e:
|
||||
+ logger.warning("POST returning 400 response, could not parse body data: %s", e)
|
||||
+ web_util.echo_json_response(self, 400, "content is invalid")
|
||||
+ return
|
||||
+
|
||||
+ if "notifications" in rest_params:
|
||||
+ if rest_params["notifications"] == "revocation":
|
||||
+ revocation_notifier.process_revocation(
|
||||
+ json_body, perform_actions, cert_path=self.server.revocation_cert_path
|
||||
+ )
|
||||
+ web_util.echo_json_response(self, 200, "Success")
|
||||
+ else:
|
||||
+ web_util.echo_json_response(self, 400, "Only /notifications/revocation is supported")
|
||||
+ return
|
||||
+
|
||||
+ if rest_params.get("keys", None) not in ["ukey", "vkey"]:
|
||||
+ web_util.echo_json_response(self, 400, "Only /keys/ukey or /keys/vkey are supported")
|
||||
+ return
|
||||
+
|
||||
+ try:
|
||||
b64_encrypted_key = json_body["encrypted_key"]
|
||||
decrypted_key = crypto.rsa_decrypt(self.server.rsaprivatekey, base64.b64decode(b64_encrypted_key))
|
||||
except (ValueError, KeyError, TypeError) as e:
|
||||
@@ -392,6 +408,7 @@ class CloudAgentHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
rsakey_path = None
|
||||
mtls_cert_enabled = False
|
||||
mtls_cert = None
|
||||
+ revocation_cert_path = None
|
||||
done = threading.Event()
|
||||
auth_tag = None
|
||||
payload = None
|
||||
@@ -456,6 +473,13 @@ class CloudAgentHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
self.mtls_cert = None
|
||||
logger.info("WARNING: mTLS disabled, Tenant and Verifier will reach out to agent via HTTP")
|
||||
|
||||
+ self.revocation_cert_path = config.get("cloud_agent", "revocation_cert")
|
||||
+ if self.revocation_cert_path == "default":
|
||||
+ self.revocation_cert_path = os.path.join(secdir, "unzipped/RevocationNotifier-cert.crt")
|
||||
+ elif self.revocation_cert_path[0] != "/":
|
||||
+ # if it is a relative, convert to absolute in work_dir
|
||||
+ self.revocation_cert_path = os.path.abspath(os.path.join(config.WORK_DIR, self.revocation_cert_path))
|
||||
+
|
||||
# attempt to get a U value from the TPM NVRAM
|
||||
nvram_u = tpm_instance.read_key_nvram()
|
||||
if nvram_u is not None:
|
||||
@@ -549,6 +573,45 @@ class CloudAgentHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
return False
|
||||
|
||||
|
||||
+# Execute revocation action
|
||||
+def perform_actions(revocation):
|
||||
+ actionlist = []
|
||||
+
|
||||
+ # load the actions from inside the keylime module
|
||||
+ actionlisttxt = config.get("cloud_agent", "revocation_actions")
|
||||
+ if actionlisttxt.strip() != "":
|
||||
+ actionlist = actionlisttxt.split(",")
|
||||
+ actionlist = [f"revocation_actions.{i}" % i for i in actionlist]
|
||||
+
|
||||
+ # load actions from unzipped
|
||||
+ secdir = secure_mount.mount()
|
||||
+ action_list_path = os.path.join(secdir, "unzipped/action_list")
|
||||
+ if os.path.exists(action_list_path):
|
||||
+ with open(action_list_path, encoding="utf-8") as f:
|
||||
+ actionlisttxt = f.read()
|
||||
+ if actionlisttxt.strip() != "":
|
||||
+ localactions = actionlisttxt.strip().split(",")
|
||||
+ for action in localactions:
|
||||
+ if not action.startswith("local_action_"):
|
||||
+ logger.warning("Invalid local action: %s. Must start with local_action_", action)
|
||||
+ else:
|
||||
+ actionlist.append(action)
|
||||
+
|
||||
+ uzpath = os.path.join(secdir, "unzipped")
|
||||
+ if uzpath not in sys.path:
|
||||
+ sys.path.append(uzpath)
|
||||
+
|
||||
+ for action in actionlist:
|
||||
+ logger.info("Executing revocation action %s", action)
|
||||
+ try:
|
||||
+ module = importlib.import_module(action)
|
||||
+ execute = getattr(module, "execute")
|
||||
+ loop = asyncio.new_event_loop()
|
||||
+ loop.run_until_complete(execute(revocation))
|
||||
+ except Exception as e:
|
||||
+ logger.warning("Exception during execution of revocation action %s: %s", action, e)
|
||||
+
|
||||
+
|
||||
def revocation_listener():
|
||||
"""
|
||||
This configures and starts the revocation listener. It is designed to be started in a separate process.
|
||||
@@ -573,42 +636,6 @@ def revocation_listener():
|
||||
# if it is a relative, convert to absolute in work_dir
|
||||
cert_path = os.path.abspath(os.path.join(config.WORK_DIR, cert_path))
|
||||
|
||||
- # Callback function handling the revocations
|
||||
- def perform_actions(revocation):
|
||||
- actionlist = []
|
||||
-
|
||||
- # load the actions from inside the keylime module
|
||||
- actionlisttxt = config.get("cloud_agent", "revocation_actions")
|
||||
- if actionlisttxt.strip() != "":
|
||||
- actionlist = actionlisttxt.split(",")
|
||||
- actionlist = [f"revocation_actions.{i}" % i for i in actionlist]
|
||||
-
|
||||
- # load actions from unzipped
|
||||
- action_list_path = os.path.join(secdir, "unzipped/action_list")
|
||||
- if os.path.exists(action_list_path):
|
||||
- with open(action_list_path, encoding="utf-8") as f:
|
||||
- actionlisttxt = f.read()
|
||||
- if actionlisttxt.strip() != "":
|
||||
- localactions = actionlisttxt.strip().split(",")
|
||||
- for action in localactions:
|
||||
- if not action.startswith("local_action_"):
|
||||
- logger.warning("Invalid local action: %s. Must start with local_action_", action)
|
||||
- else:
|
||||
- actionlist.append(action)
|
||||
-
|
||||
- uzpath = os.path.join(secdir, "unzipped")
|
||||
- if uzpath not in sys.path:
|
||||
- sys.path.append(uzpath)
|
||||
-
|
||||
- for action in actionlist:
|
||||
- logger.info("Executing revocation action %s", action)
|
||||
- try:
|
||||
- module = importlib.import_module(action)
|
||||
- execute = getattr(module, "execute")
|
||||
- asyncio.get_event_loop().run_until_complete(execute(revocation))
|
||||
- except Exception as e:
|
||||
- logger.warning("Exception during execution of revocation action %s: %s", action, e)
|
||||
-
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
--
|
||||
2.35.1
|
||||
|
356
0004-cloud_verifier-Support-notifications-revocation-REST.patch
Normal file
356
0004-cloud_verifier-Support-notifications-revocation-REST.patch
Normal file
@ -0,0 +1,356 @@
|
||||
From 16d3a31145e3d0001e6c6621adb6dbaf831cb03f Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Mon, 21 Mar 2022 13:08:29 +0100
|
||||
Subject: [PATCH 4/5] cloud_verifier: Support /notifications/revocation REST
|
||||
API
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
keylime.conf | 22 ++++--
|
||||
keylime/cloud_verifier_common.py | 16 +----
|
||||
keylime/cloud_verifier_tornado.py | 108 +++++++++++++++++++++++-------
|
||||
keylime/revocation_notifier.py | 18 ++++-
|
||||
4 files changed, 119 insertions(+), 45 deletions(-)
|
||||
|
||||
diff --git a/keylime.conf b/keylime.conf
|
||||
index fbd1119..c393e22 100644
|
||||
--- a/keylime.conf
|
||||
+++ b/keylime.conf
|
||||
@@ -269,9 +269,21 @@ max_retries = 5
|
||||
# will done as fast as possible. Floating point values accepted here.
|
||||
quote_interval = 2
|
||||
|
||||
-# Whether to turn on the zero mq based revocation notifier system.
|
||||
-# Currently this only works if you are using keylime-CA.
|
||||
-revocation_notifier = True
|
||||
+# Enable listed revocation notification methods.
|
||||
+#
|
||||
+# Available methods are:
|
||||
+#
|
||||
+# "zeromq": Enable the ZeroMQ based revocation notification method;
|
||||
+# revocation_notifier_ip and revocation_notifier_port options must be
|
||||
+# set. Currently this only works if you are using keylime-CA.
|
||||
+#
|
||||
+# "webhook": Send notification via webhook. The endpoint URL must be
|
||||
+# configured with webhook_url option. This can be used to notify other
|
||||
+# systems that do not have a Keylime agent running.
|
||||
+#
|
||||
+# "agent": Deliver notification directly to the agent via the REST
|
||||
+# protocol.
|
||||
+revocation_notifiers = zeromq
|
||||
|
||||
# The binding address and port of the revocation notifier service.
|
||||
# If the 'revocation_notifier' option is set to "true", then the verifier
|
||||
@@ -279,10 +291,6 @@ revocation_notifier = True
|
||||
revocation_notifier_ip = 127.0.0.1
|
||||
revocation_notifier_port = 8992
|
||||
|
||||
-# Enable revocation notifications via webhook. This can be used to notify other
|
||||
-# systems that do not have a Keylime agent running.
|
||||
-revocation_notifier_webhook = False
|
||||
-
|
||||
# Webhook url for revocation notifications.
|
||||
webhook_url = ''
|
||||
|
||||
diff --git a/keylime/cloud_verifier_common.py b/keylime/cloud_verifier_common.py
|
||||
index 52d6908..ab00768 100644
|
||||
--- a/keylime/cloud_verifier_common.py
|
||||
+++ b/keylime/cloud_verifier_common.py
|
||||
@@ -7,7 +7,7 @@ import ast
|
||||
import base64
|
||||
import time
|
||||
|
||||
-from keylime import config, crypto, json, keylime_logging, revocation_notifier
|
||||
+from keylime import config, crypto, json, keylime_logging
|
||||
from keylime.agentstates import AgentAttestStates
|
||||
from keylime.common import algorithms, validators
|
||||
from keylime.failure import Component, Failure
|
||||
@@ -268,14 +268,7 @@ def process_get_status(agent):
|
||||
|
||||
|
||||
# sign a message with revocation key. telling of verification problem
|
||||
-
|
||||
-
|
||||
-def notify_error(agent, msgtype="revocation", event=None):
|
||||
- send_mq = config.getboolean("cloud_verifier", "revocation_notifier")
|
||||
- send_webhook = config.getboolean("cloud_verifier", "revocation_notifier_webhook", fallback=False)
|
||||
- if not (send_mq or send_webhook):
|
||||
- return
|
||||
-
|
||||
+def prepare_error(agent, msgtype="revocation", event=None):
|
||||
# prepare the revocation message:
|
||||
revocation = {
|
||||
"type": msgtype,
|
||||
@@ -300,10 +293,7 @@ def notify_error(agent, msgtype="revocation", event=None):
|
||||
|
||||
else:
|
||||
tosend["signature"] = "none"
|
||||
- if send_mq:
|
||||
- revocation_notifier.notify(tosend)
|
||||
- if send_webhook:
|
||||
- revocation_notifier.notify_webhook(tosend)
|
||||
+ return tosend
|
||||
|
||||
|
||||
def validate_agent_data(agent_data):
|
||||
diff --git a/keylime/cloud_verifier_tornado.py b/keylime/cloud_verifier_tornado.py
|
||||
index 60abf37..a8c08d2 100644
|
||||
--- a/keylime/cloud_verifier_tornado.py
|
||||
+++ b/keylime/cloud_verifier_tornado.py
|
||||
@@ -9,6 +9,7 @@ import os
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
+from concurrent.futures import ThreadPoolExecutor
|
||||
from multiprocessing import Process
|
||||
|
||||
import tornado.ioloop
|
||||
@@ -35,6 +36,9 @@ from keylime.failure import MAX_SEVERITY_LABEL, Component, Failure
|
||||
|
||||
logger = keylime_logging.init_logging("cloudverifier")
|
||||
|
||||
+# mTLS configuration to connect to the agent
|
||||
+mtls_options = None
|
||||
+
|
||||
|
||||
try:
|
||||
engine = DBEngineManager().make_engine("cloud_verifier")
|
||||
@@ -232,11 +236,6 @@ class VersionHandler(BaseHandler):
|
||||
|
||||
|
||||
class AgentsHandler(BaseHandler):
|
||||
- mtls_options = None # Stores the cert, key and password used by the verifier for mTLS connections
|
||||
-
|
||||
- def initialize(self, mtls_options):
|
||||
- self.mtls_options = mtls_options
|
||||
-
|
||||
def head(self):
|
||||
"""HEAD not supported"""
|
||||
web_util.echo_json_response(self, 405, "HEAD not supported")
|
||||
@@ -496,9 +495,7 @@ class AgentsHandler(BaseHandler):
|
||||
mtls_cert = agent_data["mtls_cert"]
|
||||
agent_data["ssl_context"] = None
|
||||
if agent_mtls_cert_enabled and mtls_cert:
|
||||
- agent_data["ssl_context"] = web_util.generate_agent_mtls_context(
|
||||
- mtls_cert, self.mtls_options
|
||||
- )
|
||||
+ agent_data["ssl_context"] = web_util.generate_agent_mtls_context(mtls_cert, mtls_options)
|
||||
|
||||
if agent_data["ssl_context"] is None:
|
||||
logger.warning("Connecting to agent without mTLS: %s", agent_id)
|
||||
@@ -566,7 +563,7 @@ class AgentsHandler(BaseHandler):
|
||||
if not isinstance(agent, dict):
|
||||
agent = _from_db_obj(agent)
|
||||
if agent["mtls_cert"]:
|
||||
- agent["ssl_context"] = web_util.generate_agent_mtls_context(agent["mtls_cert"], self.mtls_options)
|
||||
+ agent["ssl_context"] = web_util.generate_agent_mtls_context(agent["mtls_cert"], mtls_options)
|
||||
agent["operational_state"] = states.START
|
||||
asyncio.ensure_future(process_agent(agent, states.GET_QUOTE))
|
||||
web_util.echo_json_response(self, 200, "Success")
|
||||
@@ -860,6 +857,70 @@ async def invoke_provide_v(agent):
|
||||
asyncio.ensure_future(process_agent(agent, states.GET_QUOTE))
|
||||
|
||||
|
||||
+async def invoke_notify_error(agent, tosend):
|
||||
+ if agent is None:
|
||||
+ logger.warning("Agent deleted while being processed")
|
||||
+ return
|
||||
+ kwargs = {
|
||||
+ "data": tosend,
|
||||
+ }
|
||||
+ if agent["ssl_context"]:
|
||||
+ kwargs["context"] = agent["ssl_context"]
|
||||
+ res = tornado_requests.request(
|
||||
+ "POST",
|
||||
+ f"http://{agent['ip']}:{agent['port']}/v{agent['supported_version']}/notifications/revocation",
|
||||
+ **kwargs,
|
||||
+ )
|
||||
+ response = await res
|
||||
+
|
||||
+ if response is None:
|
||||
+ logger.warning(
|
||||
+ "Empty Notify Revocation response from cloud agent %s",
|
||||
+ agent["agent_id"],
|
||||
+ )
|
||||
+ elif response.status_code != 200:
|
||||
+ logger.warning(
|
||||
+ "Unexpected Notify Revocation response error for cloud agent %s, Error: %s",
|
||||
+ agent["agent_id"],
|
||||
+ response.status_code,
|
||||
+ )
|
||||
+
|
||||
+
|
||||
+async def notify_error(agent, msgtype="revocation", event=None):
|
||||
+ notifiers = revocation_notifier.get_notifiers()
|
||||
+ if len(notifiers) == 0:
|
||||
+ return
|
||||
+
|
||||
+ tosend = cloud_verifier_common.prepare_error(agent, msgtype, event)
|
||||
+ if "webhook" in notifiers:
|
||||
+ revocation_notifier.notify_webhook(tosend)
|
||||
+ if "zeromq" in notifiers:
|
||||
+ revocation_notifier.notify(tosend)
|
||||
+ if "agent" in notifiers:
|
||||
+ verifier_id = config.get(
|
||||
+ "cloud_verifier", "cloudverifier_id", fallback=cloud_verifier_common.DEFAULT_VERIFIER_ID
|
||||
+ )
|
||||
+ session = get_session()
|
||||
+ agents = session.query(VerfierMain).filter_by(verifier_id=verifier_id).all()
|
||||
+ futures = []
|
||||
+ loop = asyncio.get_event_loop()
|
||||
+ # Notify all agents asynchronously through a thread pool
|
||||
+ with ThreadPoolExecutor() as pool:
|
||||
+ for agent_db_obj in agents:
|
||||
+ if agent_db_obj.agent_id != agent["agent_id"]:
|
||||
+ agent = _from_db_obj(agent_db_obj)
|
||||
+ if agent["mtls_cert"]:
|
||||
+ agent["ssl_context"] = web_util.generate_agent_mtls_context(agent["mtls_cert"], mtls_options)
|
||||
+ func = functools.partial(invoke_notify_error, agent, tosend)
|
||||
+ futures.append(await loop.run_in_executor(pool, func))
|
||||
+ # Wait for all tasks complete in 60 seconds
|
||||
+ try:
|
||||
+ for f in asyncio.as_completed(futures, timeout=60):
|
||||
+ await f
|
||||
+ except asyncio.TimeoutError as e:
|
||||
+ logger.error("Timeout during notifying error to agents: %s", e)
|
||||
+
|
||||
+
|
||||
async def process_agent(agent, new_operational_state, failure=Failure(Component.INTERNAL, ["verifier"])):
|
||||
# Convert to dict if the agent arg is a db object
|
||||
if not isinstance(agent, dict):
|
||||
@@ -900,7 +961,7 @@ async def process_agent(agent, new_operational_state, failure=Failure(Component.
|
||||
|
||||
# issue notification for invalid quotes
|
||||
if new_operational_state == states.INVALID_QUOTE:
|
||||
- cloud_verifier_common.notify_error(agent, event=failure.highest_severity_event)
|
||||
+ await notify_error(agent, event=failure.highest_severity_event)
|
||||
|
||||
# When the failure is irrecoverable we stop polling the agent
|
||||
if not failure.recoverable or failure.highest_severity == MAX_SEVERITY_LABEL:
|
||||
@@ -975,9 +1036,7 @@ async def process_agent(agent, new_operational_state, failure=Failure(Component.
|
||||
)
|
||||
failure.add_event("not_reachable", "agent was not reachable from verifier", False)
|
||||
if agent["first_verified"]: # only notify on previously good agents
|
||||
- cloud_verifier_common.notify_error(
|
||||
- agent, msgtype="comm_error", event=failure.highest_severity_event
|
||||
- )
|
||||
+ await notify_error(agent, msgtype="comm_error", event=failure.highest_severity_event)
|
||||
else:
|
||||
logger.debug("Communication error for new agent. No notification will be sent")
|
||||
await process_agent(agent, states.FAILED, failure)
|
||||
@@ -1004,7 +1063,7 @@ async def process_agent(agent, new_operational_state, failure=Failure(Component.
|
||||
maxr,
|
||||
)
|
||||
failure.add_event("not_reachable_v", "agent was not reachable to provide V", False)
|
||||
- cloud_verifier_common.notify_error(agent, msgtype="comm_error", event=failure.highest_severity_event)
|
||||
+ await notify_error(agent, msgtype="comm_error", event=failure.highest_severity_event)
|
||||
await process_agent(agent, states.FAILED, failure)
|
||||
else:
|
||||
agent["operational_state"] = states.PROVIDE_V
|
||||
@@ -1031,7 +1090,7 @@ async def process_agent(agent, new_operational_state, failure=Failure(Component.
|
||||
await process_agent(agent, states.FAILED, failure)
|
||||
|
||||
|
||||
-async def activate_agents(verifier_id, verifier_ip, verifier_port, mtls_options):
|
||||
+async def activate_agents(verifier_id, verifier_ip, verifier_port):
|
||||
session = get_session()
|
||||
aas = get_AgentAttestStates()
|
||||
try:
|
||||
@@ -1100,7 +1159,7 @@ def main():
|
||||
# print out API versions we support
|
||||
keylime_api_version.log_api_versions(logger)
|
||||
|
||||
- context, mtls_options = web_util.init_mtls(logger=logger)
|
||||
+ context, server_mtls_options = web_util.init_mtls(logger=logger)
|
||||
|
||||
# Check for user defined CA to connect to agent
|
||||
agent_mtls_cert = config.get("cloud_verifier", "agent_mtls_cert", fallback=None)
|
||||
@@ -1108,12 +1167,15 @@ def main():
|
||||
agent_mtls_private_key_pw = config.get("cloud_verifier", "agent_mtls_private_key_pw", fallback=None)
|
||||
|
||||
# Only set custom options if the cert should not be the same as used by the verifier
|
||||
- if agent_mtls_cert != "CV":
|
||||
+ global mtls_options
|
||||
+ if agent_mtls_cert == "CV":
|
||||
+ mtls_options = server_mtls_options
|
||||
+ else:
|
||||
mtls_options = (agent_mtls_cert, agent_mtls_private_key, agent_mtls_private_key_pw)
|
||||
|
||||
app = tornado.web.Application(
|
||||
[
|
||||
- (r"/v?[0-9]+(?:\.[0-9]+)?/agents/.*", AgentsHandler, {"mtls_options": mtls_options}),
|
||||
+ (r"/v?[0-9]+(?:\.[0-9]+)?/agents/.*", AgentsHandler),
|
||||
(r"/v?[0-9]+(?:\.[0-9]+)?/allowlists/.*", AllowlistHandler),
|
||||
(r"/versions?", VersionHandler),
|
||||
(r".*", MainHandler),
|
||||
@@ -1149,17 +1211,17 @@ def main():
|
||||
server.start()
|
||||
if task_id == 0:
|
||||
# Reactivate agents
|
||||
- asyncio.ensure_future(
|
||||
- activate_agents(cloudverifier_id, cloudverifier_host, cloudverifier_port, mtls_options)
|
||||
- )
|
||||
+ asyncio.ensure_future(activate_agents(cloudverifier_id, cloudverifier_host, cloudverifier_port))
|
||||
tornado.ioloop.IOLoop.current().start()
|
||||
logger.debug("Server %s stopped.", task_id)
|
||||
sys.exit(0)
|
||||
|
||||
processes = []
|
||||
|
||||
+ run_revocation_notifier = "zeromq" in revocation_notifier.get_notifiers()
|
||||
+
|
||||
def sig_handler(*_):
|
||||
- if config.getboolean("cloud_verifier", "revocation_notifier"):
|
||||
+ if run_revocation_notifier:
|
||||
revocation_notifier.stop_broker()
|
||||
for p in processes:
|
||||
p.join()
|
||||
@@ -1167,7 +1229,7 @@ def main():
|
||||
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
- if config.getboolean("cloud_verifier", "revocation_notifier"):
|
||||
+ if run_revocation_notifier:
|
||||
logger.info(
|
||||
"Starting service for revocation notifications on port %s",
|
||||
config.getint("cloud_verifier", "revocation_notifier_port"),
|
||||
diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py
|
||||
index 7cfe0e5..0628a64 100644
|
||||
--- a/keylime/revocation_notifier.py
|
||||
+++ b/keylime/revocation_notifier.py
|
||||
@@ -22,8 +22,22 @@ broker_proc: Optional[Process] = None
|
||||
_SOCKET_PATH = "/var/run/keylime/keylime.verifier.ipc"
|
||||
|
||||
|
||||
+# return the revocation notification methods for cloud verifier
|
||||
+def get_notifiers():
|
||||
+ notifiers = set(config.get("cloud_verifier", "revocation_notifiers", fallback="").split(","))
|
||||
+ if ("zeromq" not in notifiers) and config.getboolean("cloud_verifier", "revocation_notifier", fallback=False):
|
||||
+ logger.warning("Warning: 'revocation_notifier' option is deprecated; use 'revocation_notifiers'")
|
||||
+ notifiers.add("zeromq")
|
||||
+ if ("webhook" not in notifiers) and config.getboolean(
|
||||
+ "cloud_verifier", "revocation_notifier_webhook", fallback=False
|
||||
+ ):
|
||||
+ logger.warning("Warning: 'revocation_notifier_webhook' option is deprecated; use 'revocation_notifiers'")
|
||||
+ notifiers.add("webhook")
|
||||
+ return notifiers.intersection({"zeromq", "webhook", "agent"})
|
||||
+
|
||||
+
|
||||
def start_broker():
|
||||
- assert config.getboolean("cloud_verifier", "revocation_notifier")
|
||||
+ assert "zeromq" in get_notifiers()
|
||||
try:
|
||||
import zmq # pylint: disable=import-outside-toplevel
|
||||
except ImportError as error:
|
||||
@@ -78,7 +92,7 @@ def stop_broker():
|
||||
|
||||
|
||||
def notify(tosend):
|
||||
- assert config.getboolean("cloud_verifier", "revocation_notifier")
|
||||
+ assert "zeromq" in get_notifiers()
|
||||
try:
|
||||
import zmq # pylint: disable=import-outside-toplevel
|
||||
except ImportError as error:
|
||||
--
|
||||
2.35.1
|
||||
|
117
0005-Use-python3-gpg-instead-of-python3-gnupg.patch
Normal file
117
0005-Use-python3-gpg-instead-of-python3-gnupg.patch
Normal file
@ -0,0 +1,117 @@
|
||||
From 49bc0a3afbbe3740bb857b530440364b021a865f Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Correia <scorreia@redhat.com>
|
||||
Date: Fri, 17 Jun 2022 19:57:17 -0300
|
||||
Subject: [PATCH 5/5] Use python3-gpg instead of python3-gnupg
|
||||
|
||||
The former uses GPGME and is the recommended way of using GnuPG from
|
||||
applications, by the GnuPG initiative, as it provides a better
|
||||
documented API [1][2].
|
||||
|
||||
python-gpg is also already present in some distros, e.g. Fedora and
|
||||
CentOS Stream, as it is a dependency of their package manager (dnf).
|
||||
|
||||
It is also available in other major distros such as Debian, Ubuntu,
|
||||
OpenSUSE, so no disruptions are to be expected regarding packaging.
|
||||
|
||||
[1] https://gnupg.org/software/gpgme/index.html
|
||||
[2] https://wiki.python.org/moin/GnuPrivacyGuard
|
||||
---
|
||||
installer.sh | 6 +++---
|
||||
keylime/signing.py | 27 +++++++++++++--------------
|
||||
requirements.txt | 3 +--
|
||||
3 files changed, 17 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/installer.sh b/installer.sh
|
||||
index 6618e1d..4355b33 100755
|
||||
--- a/installer.sh
|
||||
+++ b/installer.sh
|
||||
@@ -58,7 +58,7 @@ case "$ID" in
|
||||
echo "${ID} selected."
|
||||
PACKAGE_MGR=$(command -v apt-get)
|
||||
PYTHON_PREIN="git patch"
|
||||
- PYTHON_DEPS="python3 python3-pip python3-dev python3-setuptools python3-zmq python3-tornado python3-cryptography python3-requests python3-psutil gcc g++ libssl-dev swig python3-yaml python3-gnupg python3-lark wget"
|
||||
+ PYTHON_DEPS="python3 python3-pip python3-dev python3-setuptools python3-zmq python3-tornado python3-cryptography python3-requests python3-psutil gcc g++ libssl-dev swig python3-yaml python3-gpg python3-lark wget"
|
||||
if [ "$(uname -m)" = "x86_64" ]; then
|
||||
PYTHON_DEPS+=" libefivar-dev"
|
||||
fi
|
||||
@@ -96,7 +96,7 @@ case "$ID" in
|
||||
PACKAGE_MGR=$(command -v dnf)
|
||||
NEED_EPEL=1
|
||||
PYTHON_PREIN="python3 python3-devel python3-setuptools python3-pip"
|
||||
- PYTHON_DEPS="gcc gcc-c++ openssl-devel python3-yaml python3-requests swig python3-cryptography wget git python3-tornado python3-zmq python3-gnupg python3-psutil"
|
||||
+ PYTHON_DEPS="gcc gcc-c++ openssl-devel python3-yaml python3-requests swig python3-cryptography wget git python3-tornado python3-zmq python3-gpg python3-psutil"
|
||||
if [ "$(uname -m)" = "x86_64" ]; then
|
||||
PYTHON_DEPS+=" efivar-libs"
|
||||
fi
|
||||
@@ -116,7 +116,7 @@ case "$ID" in
|
||||
echo "${ID} selected."
|
||||
PACKAGE_MGR=$(command -v dnf)
|
||||
PYTHON_PREIN="python3 python3-devel python3-setuptools git wget patch"
|
||||
- PYTHON_DEPS="python3-pip gcc gcc-c++ openssl-devel swig python3-pyyaml python3-zmq python3-cryptography python3-tornado python3-requests python3-gnupg yaml-cpp-devel procps-ng python3-psutil python3-lark-parser"
|
||||
+ PYTHON_DEPS="python3-pip gcc gcc-c++ openssl-devel swig python3-pyyaml python3-zmq python3-cryptography python3-tornado python3-requests python3-gpg yaml-cpp-devel procps-ng python3-psutil python3-lark-parser"
|
||||
if [ "$(uname -m)" = "x86_64" ]; then
|
||||
PYTHON_DEPS+=" efivar-devel"
|
||||
fi
|
||||
diff --git a/keylime/signing.py b/keylime/signing.py
|
||||
index 1353c1e..a1be9c7 100644
|
||||
--- a/keylime/signing.py
|
||||
+++ b/keylime/signing.py
|
||||
@@ -5,7 +5,7 @@ Copyright 2017 Massachusetts Institute of Technology.
|
||||
|
||||
import tempfile
|
||||
|
||||
-import gnupg
|
||||
+import gpg
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
@@ -55,19 +55,18 @@ def verify_signature(key, sig, file):
|
||||
|
||||
# PGP
|
||||
if key_header == "-----BEGIN PGP PUBLIC KEY BLOCK-----":
|
||||
- gpg = gnupg.GPG()
|
||||
- logger.debug("Importing GPG key")
|
||||
- gpg_imported = gpg.import_keys(key.decode("utf-8"))
|
||||
- if gpg_imported.count == 1: # pylint: disable=E1101
|
||||
- logger.debug("GPG key successfully imported")
|
||||
- else:
|
||||
- raise Exception("Unable to import GPG key")
|
||||
-
|
||||
- # The Python PGP library won't let you read a signature from memory, hence this hack.
|
||||
- with tempfile.NamedTemporaryFile() as temp_sig:
|
||||
- temp_sig.write(sig)
|
||||
- temp_sig.flush()
|
||||
- verified = gpg.verify_data(temp_sig.name, file)
|
||||
+ verified = False
|
||||
+ with tempfile.TemporaryDirectory() as gpg_homedir:
|
||||
+ ctx = gpg.Context(home_dir=gpg_homedir)
|
||||
+ try:
|
||||
+ logger.debug("Importing GPG key")
|
||||
+ result = ctx.key_import(key)
|
||||
+ except Exception as e:
|
||||
+ raise Exception("Unable to import GPG key") from e
|
||||
+
|
||||
+ if result is not None and hasattr(result, "considered") is True:
|
||||
+ _, result = ctx.verify(file, sig)
|
||||
+ verified = result.signatures[0].status == 0
|
||||
|
||||
# OpenSSL
|
||||
elif key_header == "-----BEGIN PUBLIC KEY-----":
|
||||
diff --git a/requirements.txt b/requirements.txt
|
||||
index d31eabc..ca3fac3 100644
|
||||
--- a/requirements.txt
|
||||
+++ b/requirements.txt
|
||||
@@ -10,8 +10,7 @@ pyyaml>=3.11 # MIT
|
||||
requests>=2.6 # Apache-2.0
|
||||
sqlalchemy>=1.3 # MIT
|
||||
alembic>=1.1.0 # MIT
|
||||
-python-gnupg>=0.4.6 # BSD
|
||||
packaging>=20.0 #BSD
|
||||
psutil>=5.4.2 # BSD
|
||||
# Note that lark was renamed from lark-parser with 1.0.0 release
|
||||
-lark>=1.0.0 # MIT
|
||||
\ No newline at end of file
|
||||
+lark>=1.0.0 # MIT
|
||||
--
|
||||
2.35.1
|
||||
|
8
gating.yaml
Normal file
8
gating.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
--- !Policy
|
||||
product_versions:
|
||||
- rhel-9
|
||||
decision_context: osci_compose_gate
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.openstack-swtmp.functional}
|
||||
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.beaker-tpm-ima.functional}
|
||||
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.beaker-beaker-swtpm-multihost.functional}
|
244
keylime.spec
Normal file
244
keylime.spec
Normal file
@ -0,0 +1,244 @@
|
||||
%global srcname keylime
|
||||
|
||||
Name: keylime
|
||||
Version: 6.4.1
|
||||
Release: %{?autorelease}%{!?autorelease:1%{?dist}}
|
||||
Summary: Open source TPM software for Bootstrapping and Maintaining Trust
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
URL: https://github.com/keylime/keylime
|
||||
Source0: https://github.com/keylime/keylime/archive/refs/tags/v%{version}.tar.gz
|
||||
Source1: %{srcname}.sysusers
|
||||
|
||||
Patch: 0001-Improve-error-handling-when-doing-signature-verifica.patch
|
||||
# Agent-Local revocation.
|
||||
Patch: 0002-revocation_notifier-Factor-out-revocation-message-pr.patch
|
||||
Patch: 0003-keylime_agent-Support-notifications-revocation-REST-.patch
|
||||
Patch: 0004-cloud_verifier-Support-notifications-revocation-REST.patch
|
||||
# python-gpg.
|
||||
Patch: 0005-Use-python3-gpg-instead-of-python3-gnupg.patch
|
||||
|
||||
License: ASL 2.0 and MIT
|
||||
|
||||
BuildRequires: git-core
|
||||
BuildRequires: swig
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-dbus
|
||||
BuildRequires: python3-setuptools
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
Requires: python3-%{srcname} = %{version}-%{release}
|
||||
Requires: %{srcname}-base = %{version}-%{release}
|
||||
Requires: %{srcname}-verifier = %{version}-%{release}
|
||||
Requires: %{srcname}-registrar = %{version}-%{release}
|
||||
Requires: %{srcname}-tenant = %{version}-%{release}
|
||||
|
||||
# Agent.
|
||||
Requires: keylime-agent
|
||||
Suggests: keylime-agent-rust
|
||||
|
||||
%{?python_enable_dependency_generator}
|
||||
%description
|
||||
Keylime is a TPM based highly scalable remote boot attestation
|
||||
and runtime integrity measurement solution.
|
||||
|
||||
%package base
|
||||
Summary: The base package contains the default configuration
|
||||
License: MIT
|
||||
|
||||
|
||||
Requires(pre): shadow-utils
|
||||
Requires: efivar-libs
|
||||
Requires: procps-ng
|
||||
Requires: tpm2-tss
|
||||
Requires: tpm2-tools
|
||||
|
||||
|
||||
%description base
|
||||
The base package contains the Keylime default configuration
|
||||
|
||||
%package -n python3-%{srcname}
|
||||
Summary: The Python Keylime module
|
||||
License: MIT
|
||||
|
||||
Requires: %{srcname}-base = %{version}-%{release}
|
||||
%{?python_provide:%python_provide python3-%{srcname}}
|
||||
|
||||
Requires: python3-tornado
|
||||
Requires: python3-sqlalchemy
|
||||
Requires: python3-alembic
|
||||
Requires: python3-cryptography
|
||||
Requires: python3-pyyaml
|
||||
Requires: python3-packaging
|
||||
Requires: python3-requests
|
||||
Requires: python3-gpg
|
||||
Requires: python3-lark-parser
|
||||
|
||||
|
||||
%description -n python3-%{srcname}
|
||||
The python3-keylime module implements the functionality used
|
||||
by Keylime components.
|
||||
|
||||
%package verifier
|
||||
Summary: The Python Keylime Verifier component
|
||||
License: MIT
|
||||
|
||||
Requires: %{srcname}-base = %{version}-%{release}
|
||||
Requires: python3-%{srcname} = %{version}-%{release}
|
||||
|
||||
%description verifier
|
||||
The Keylime Verifier continuously verifies the integrity state
|
||||
of the machine that the agent is running on.
|
||||
|
||||
%package registrar
|
||||
Summary: The Keylime Registrar component
|
||||
License: MIT
|
||||
|
||||
Requires: %{srcname}-base = %{version}-%{release}
|
||||
Requires: python3-%{srcname} = %{version}-%{release}
|
||||
|
||||
%description registrar
|
||||
The Keylime Registrar is a database of all agents registered
|
||||
with Keylime and hosts the public keys of the TPM vendors.
|
||||
|
||||
%package tenant
|
||||
Summary: The Python Keylime Tenant
|
||||
License: MIT
|
||||
|
||||
Requires: %{srcname}-base = %{version}-%{release}
|
||||
Requires: python3-%{srcname} = %{version}-%{release}
|
||||
|
||||
|
||||
%description tenant
|
||||
The Keylime Tenant can be used to provision a Keylime Agent.
|
||||
|
||||
%prep
|
||||
%autosetup -S git -n %{srcname}-%{version}
|
||||
|
||||
%build
|
||||
%py3_build
|
||||
|
||||
%install
|
||||
%py3_install
|
||||
mkdir -p %{buildroot}/%{_sharedstatedir}/%{srcname}
|
||||
mkdir -p --mode=0700 %{buildroot}/%{_rundir}/%{srcname}
|
||||
mkdir -p --mode=0700 %{buildroot}/%{_localstatedir}/log/%{srcname}
|
||||
|
||||
# Remove agent and webapp.
|
||||
rm -f %{buildroot}/%{_bindir}/%{srcname}_agent
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/__pycache__/%{srcname}_agent*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/cmd/__pycache__/agent.*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/cmd/agent.*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/%{srcname}_agent.*
|
||||
|
||||
rm -f %{buildroot}/%{_bindir}/%{srcname}_webapp
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/__pycache__/tenant_webapp.*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/cmd/__pycache__/webapp.*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/cmd/webapp.*
|
||||
rm -f %{buildroot}%{python3_sitelib}/%{srcname}/tenant_webapp.*
|
||||
rm -rf %{buildroot}%{python3_sitelib}/%{srcname}/static/
|
||||
|
||||
# Remove misc progs.
|
||||
rm -f %{buildroot}/%{_bindir}/%{srcname}_ima_emulator
|
||||
rm -f %{buildroot}/%{_bindir}/%{srcname}_userdata_encrypt
|
||||
|
||||
# Disable zeromq revocation notifier, as there is no zeromq in RHEL.
|
||||
# 6.4.1.
|
||||
# Agent-Local revocation.
|
||||
sed -e 's/^revocation_notifiers[[:space:]]*=.*/revocation_notifiers = agent/g' \
|
||||
-i %{srcname}.conf
|
||||
|
||||
# Setting up the agent to use keylime:tss user/group after dropping privileges.
|
||||
sed -e 's/^run_as[[:space:]]*=.*/run_as = keylime:tss/g' -i %{srcname}.conf
|
||||
|
||||
# Using sha256 for tpm_hash_alg.
|
||||
sed -e 's/^tpm_hash_alg[[:space:]]*=.*/tpm_hash_alg = sha256/g' -i %{srcname}.conf
|
||||
|
||||
install -Dpm 600 %{srcname}.conf \
|
||||
%{buildroot}%{_sysconfdir}/%{srcname}.conf
|
||||
|
||||
install -Dpm 644 ./services/%{srcname}_verifier.service \
|
||||
%{buildroot}%{_unitdir}/%{srcname}_verifier.service
|
||||
|
||||
install -Dpm 644 ./services/%{srcname}_registrar.service \
|
||||
%{buildroot}%{_unitdir}/%{srcname}_registrar.service
|
||||
|
||||
cp -r ./tpm_cert_store %{buildroot}%{_sharedstatedir}/keylime/
|
||||
|
||||
install -p -d %{buildroot}/%{_tmpfilesdir}
|
||||
cat > %{buildroot}/%{_tmpfilesdir}/%{srcname}.conf << EOF
|
||||
d %{_rundir}/%{srcname} 0700 %{srcname} %{srcname} -
|
||||
EOF
|
||||
|
||||
install -p -D -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/%{srcname}.conf
|
||||
|
||||
%pre base
|
||||
%sysusers_create_compat %{SOURCE1}
|
||||
exit 0
|
||||
|
||||
%posttrans base
|
||||
[ -f %{_sysconfdir}/%{srcname}.conf ] && \
|
||||
chmod 600 %{_sysconfdir}/%{srcname}.conf && \
|
||||
chown %{srcname} %{_sysconfdir}/%{srcname}.conf
|
||||
[ -d %{_sharedstatedir}/%{srcname} ] && \
|
||||
chown -R %{srcname} %{_sharedstatedir}/%{srcname}/
|
||||
[ -d %{_localstatedir}/log/%{srcname} ] && \
|
||||
chown -R %{srcname} %{_localstatedir}/log/%{srcname}/
|
||||
exit 0
|
||||
|
||||
%post verifier
|
||||
%systemd_post %{srcname}_verifier.service
|
||||
|
||||
%post registrar
|
||||
%systemd_post %{srcname}_registrar.service
|
||||
|
||||
%preun verifier
|
||||
%systemd_preun %{srcname}_verifier.service
|
||||
|
||||
%preun registrar
|
||||
%systemd_preun %{srcname}_registrar.service
|
||||
|
||||
%postun verifier
|
||||
%systemd_postun_with_restart %{srcname}_verifier.service
|
||||
|
||||
%postun registrar
|
||||
%systemd_postun_with_restart %{srcname}_registrar.service
|
||||
|
||||
%files verifier
|
||||
%license LICENSE
|
||||
%{_bindir}/%{srcname}_verifier
|
||||
%{_bindir}/%{srcname}_ca
|
||||
%{_bindir}/%{srcname}_migrations_apply
|
||||
%{_unitdir}/keylime_verifier.service
|
||||
|
||||
%files registrar
|
||||
%license LICENSE
|
||||
%{_bindir}/%{srcname}_registrar
|
||||
%{_unitdir}/keylime_registrar.service
|
||||
|
||||
%files tenant
|
||||
%license LICENSE
|
||||
%{_bindir}/%{srcname}_tenant
|
||||
|
||||
%files -n python3-%{srcname}
|
||||
%license LICENSE
|
||||
%{python3_sitelib}/%{srcname}-*.egg-info/
|
||||
%{python3_sitelib}/%{srcname}
|
||||
|
||||
%files base
|
||||
%license LICENSE keylime/static/icons/ICON-LICENSE
|
||||
%doc README.md
|
||||
%config(noreplace) %attr(600,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}.conf
|
||||
%attr(700,%{srcname},%{srcname}) %dir %{_rundir}/%{srcname}
|
||||
%attr(700,%{srcname},%{srcname}) %dir %{_localstatedir}/log/%{srcname}
|
||||
%attr(700,%{srcname},%{srcname}) %{_sharedstatedir}/%{srcname}
|
||||
%{_tmpfilesdir}/%{srcname}.conf
|
||||
%{_sysusersdir}/%{srcname}.conf
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
|
||||
%changelog
|
||||
%autochangelog
|
2
keylime.sysusers
Normal file
2
keylime.sysusers
Normal file
@ -0,0 +1,2 @@
|
||||
u keylime - "Keylime unprivileged user" /var/lib/keylime /usr/sbin/nologin
|
||||
m keylime tss
|
Loading…
Reference in New Issue
Block a user