Skip to content

Commit

Permalink
Encrypt keys before saving in OMAP file
Browse files Browse the repository at this point in the history
Fixes #960

Signed-off-by: Gil Bregman <[email protected]>
  • Loading branch information
gbregman committed Dec 19, 2024
1 parent 719a6ee commit 5e02521
Show file tree
Hide file tree
Showing 20 changed files with 1,117 additions and 484 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,5 @@ DHCHAP_KEY6="DHHC-1:01:Bu4tZd7X2oW7XxmVH5tGCdoS30pDX6bZvexHYoudeVlJW9yz:"
DHCHAP_KEY7="DHHC-1:01:JPJkDQ2po2FfLmKYlTF/sJ2HzVO/FKWxgXKE/H6XfL8ogQ1T:"
DHCHAP_KEY8="DHHC-1:01:e0B0vDxKleDzYVtG42xqFvoWZfiufkoywmfRKrETzayRdf1j:"
DHCHAP_KEY9="DHHC-1:01:KD+sfH3/o2bRQoV0ESjBUywQlMnSaYpZISUbVa0k0nsWpNST:"
DHCHAP_KEY10="DHHC-1:00:rWf0ZFYO7IgWGttM8w6jUrAY4cTQyqyXPdmxHeOSve3w5QU9:"
DHCHAP_KEY11="DHHC-1:02:j3uUz05r5aQy42vX4tDXqVf9HgUPPdEp3kXTgUWl9EphsG7jwpr9KSIt3bmRLXBijPTIDQ==:"
6 changes: 4 additions & 2 deletions ceph-nvmeof.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ state_update_notify = True
state_update_timeout_in_msec = 2000
state_update_interval_sec = 5
enable_spdk_discovery_controller = False
enable_key_encryption = True
encryption_key = /etc/ceph/encryption.key
rebalance_period_sec = 7
max_gws_in_grp = 16
max_ns_to_change_lb_grp = 8
Expand All @@ -27,12 +29,12 @@ max_ns_to_change_lb_grp = 8
#enable_prometheus_exporter = True
#prometheus_exporter_ssl = True
#prometheus_port = 10008
#prometheus_bdev_pools = rbd
#prometheus_bdev_pools =
#prometheus_stats_interval = 10
#verify_nqns = True
#allowed_consecutive_spdk_ping_failures = 1
#spdk_ping_interval_in_seconds = 2.0
#max_hosts_per_namespace = 1
#max_hosts_per_namespace = 8
#max_namespaces_with_netmask = 1000
#max_subsystems = 128
#max_namespaces = 1024
Expand Down
53 changes: 44 additions & 9 deletions control/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ def gw_set_log_level(self, args):
gw_actions.append({"name" : "get_log_level", "args" : [], "help" : "Get gateway's log level"})
gw_actions.append({"name" : "set_log_level", "args" : gw_set_log_level_args, "help" : "Set gateway's log level"})
gw_choices = get_actions(gw_actions)

@cli.cmd(gw_actions)
def gw(self, args):
"""Gateway commands"""
Expand Down Expand Up @@ -655,6 +656,7 @@ def spdk_log_level_set(self, args):
spdk_log_actions.append({"name" : "set", "args" : spdk_log_set_args, "help" : "Set SPDK log levels and nvmf log flags"})
spdk_log_actions.append({"name" : "disable", "args" : spdk_log_disable_args, "help" : "Disable SPDK nvmf log flags"})
spdk_log_choices = get_actions(spdk_log_actions)

@cli.cmd(spdk_log_actions)
def spdk_log_level(self, args):
"""SPDK nvmf log level commands"""
Expand All @@ -676,6 +678,9 @@ def subsystem_add(self, args):
if args.subsystem == GatewayUtils.DISCOVERY_NQN:
self.cli.parser.error("Can't add a discovery subsystem")

if args.dhchap_key == "":
self.cli.parser.error("DH-HMAC-CHAP key can't be empty")

req = pb2.create_subsystem_req(subsystem_nqn=args.subsystem,
serial_number=args.serial_number,
max_namespaces=args.max_namespaces,
Expand Down Expand Up @@ -769,6 +774,11 @@ def subsystem_list(self, args):
if args.format == "text" or args.format == "plain":
if subsystems.status == 0:
subsys_list = []
created_without_key = False
for s in subsystems.subsystems:
if s.created_without_key:
created_without_key = True
break
for s in subsystems.subsystems:
if args.subsystem and args.subsystem != s.nqn:
err_func("Failure listing subsystem {args.subsystem}: Got subsystem {s.nqn} instead")
Expand All @@ -780,15 +790,20 @@ def subsystem_list(self, args):
has_dhchap = "Yes" if s.has_dhchap_key else "No"
allow_any = "Yes" if s.allow_any_host else "No"
one_subsys = [s.subtype, s.nqn, s.serial_number, ctrls_id, s.namespace_count, s.max_namespaces, allow_any, has_dhchap]
if created_without_key:
one_subsys.append("Yes" if s.created_without_key else "No")
subsys_list.append(one_subsys)
if len(subsys_list) > 0:
if args.format == "text":
table_format = "fancy_grid"
else:
table_format = "plain"
headers_list = ["Subtype", "NQN", "Serial\nNumber", "Controller IDs",
"Namespace\nCount", "Max\nNamespaces", "Allow\nAny Host", "DHCHAP\nKey"]
if created_without_key:
headers_list.append("Created\nWithout Key")
subsys_out = tabulate(subsys_list,
headers = ["Subtype", "NQN", "Serial\nNumber", "Controller IDs",
"Namespace\nCount", "Max\nNamespaces", "Allow\nAny Host", "DHCHAP\nKey"],
headers = headers_list,
tablefmt=table_format)
prefix = "Subsystems"
if args.subsystem:
Expand Down Expand Up @@ -829,6 +844,9 @@ def subsystem_change_key(self, args):
rc = 0
out_func, err_func = self.get_output_functions(args)

if args.dhchap_key == "":
self.cli.parser.error("DH-HMAC-CHAP key can't be empty")

req = pb2.change_subsystem_key_req(subsystem_nqn=args.subsystem, dhchap_key=args.dhchap_key)
try:
ret = self.stub.change_subsystem_key(req)
Expand Down Expand Up @@ -884,6 +902,7 @@ def subsystem_change_key(self, args):
subsystem_actions.append({"name" : "list", "args" : subsys_list_args, "help" : "List subsystems"})
subsystem_actions.append({"name" : "change_key", "args" : subsys_change_key_args, "help" : "Change subsystem key"})
subsystem_choices = get_actions(subsystem_actions)

@cli.cmd(subsystem_actions)
def subsystem(self, args):
"""Subsystem commands"""
Expand Down Expand Up @@ -1026,11 +1045,11 @@ def listener_list(self, args):
if args.format == "text" or args.format == "plain":
if listeners_info.status == 0:
listeners_list = []
for l in listeners_info.listeners:
adrfam = GatewayEnumUtils.get_key_from_value(pb2.AddressFamily, l.adrfam)
for lstnr in listeners_info.listeners:
adrfam = GatewayEnumUtils.get_key_from_value(pb2.AddressFamily, lstnr.adrfam)
adrfam = self.format_adrfam(adrfam)
secure = "Yes" if l.secure else "No"
listeners_list.append([l.host_name, l.trtype, adrfam, f"{l.traddr}:{l.trsvcid}", secure])
secure = "Yes" if lstnr.secure else "No"
listeners_list.append([lstnr.host_name, lstnr.trtype, adrfam, f"{lstnr.traddr}:{lstnr.trsvcid}", secure])
if len(listeners_list) > 0:
if args.format == "text":
table_format = "fancy_grid"
Expand Down Expand Up @@ -1086,6 +1105,7 @@ def listener_list(self, args):
listener_actions.append({"name" : "del", "args" : listener_del_args, "help" : "Delete a listener"})
listener_actions.append({"name" : "list", "args" : listener_list_args, "help" : "List listeners"})
listener_choices = get_actions(listener_actions)

@cli.cmd(listener_actions)
def listener(self, args):
"""Listener commands"""
Expand All @@ -1109,6 +1129,12 @@ def host_add(self, args):
if len(args.host_nqn) > 1:
self.cli.parser.error(f"Can't have more than one host NQN when PSK keys are used")

if args.dhchap_key == "":
self.cli.parser.error("DH-HMAC-CHAP key can't be empty")

if args.psk == "":
self.cli.parser.error("PSK key can't be empty")

if args.dhchap_key:
if len(args.host_nqn) > 1:
self.cli.parser.error(f"Can't have more than one host NQN when DH-HMAC-CHAP keys are used")
Expand Down Expand Up @@ -1222,6 +1248,9 @@ def host_change_key(self, args):
if args.host_nqn == "*":
self.cli.parser.error(f"Can't change keys for host NQN '*', please use a real NQN")

if args.dhchap_key == "":
self.cli.parser.error("DH-HMAC-CHAP key can't be empty")

req = pb2.change_host_key_req(subsystem_nqn=args.subsystem, host_nqn=args.host_nqn,
dhchap_key=args.dhchap_key)
try:
Expand Down Expand Up @@ -1272,14 +1301,16 @@ def host_list(self, args):
for h in hosts_info.hosts:
use_psk = "Yes" if h.use_psk else "No"
use_dhchap = "Yes" if h.use_dhchap else "No"
hosts_list.append([h.nqn, use_psk, use_dhchap])
one_host = [h.nqn, use_psk, use_dhchap]
hosts_list.append(one_host)
if len(hosts_list) > 0:
if args.format == "text":
table_format = "fancy_grid"
else:
table_format = "plain"
headers_list = ["Host NQN", "Uses PSK", "Uses DHCHAP"]
hosts_out = tabulate(hosts_list,
headers = ["Host NQN", "Uses PSK", "Uses DHCHAP"],
headers = headers_list,
tablefmt=table_format, stralign="center")
out_func(f"Hosts allowed to access {args.subsystem}:\n{hosts_out}")
else:
Expand Down Expand Up @@ -1327,6 +1358,7 @@ def host_list(self, args):
host_actions.append({"name" : "list", "args" : host_list_args, "help" : "List subsystem's host access"})
host_actions.append({"name" : "change_key", "args" : host_change_key_args, "help" : "Change host's inband authentication keys"})
host_choices = get_actions(host_actions)

@cli.cmd(host_actions)
def host(self, args):
"""Host commands"""
Expand Down Expand Up @@ -1406,6 +1438,7 @@ def connection_list(self, args):
connection_actions = []
connection_actions.append({"name" : "list", "args" : connection_list_args, "help" : "List active connections"})
connection_choices = get_actions(connection_actions)

@cli.cmd(connection_actions)
def connection(self, args):
"""Connection commands"""
Expand Down Expand Up @@ -1601,7 +1634,7 @@ def get_size_in_bytes(self, sz):
try:
sz = sz.strip()
int_size = int(sz)
except:
except Exception:
self.cli.parser.error(f"Size {sz} must be numeric")

int_size *= multiply
Expand Down Expand Up @@ -2060,6 +2093,7 @@ def ns_del_host(self, args):
ns_actions.append({"name" : "add_host", "args" : ns_add_host_args_list, "help" : "Add a host to a namespace"})
ns_actions.append({"name" : "del_host", "args" : ns_del_host_args_list, "help" : "Delete a host from a namespace"})
ns_choices = get_actions(ns_actions)

@cli.cmd(ns_actions, ["ns"])
def namespace(self, args):
"""Namespace commands"""
Expand Down Expand Up @@ -2135,5 +2169,6 @@ def main(args=None) -> int:

return main_common(client, parsed_args)


if __name__ == "__main__":
sys.exit(main())
5 changes: 4 additions & 1 deletion control/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .config import GatewayConfig
from .state import GatewayState, LocalGatewayState, OmapGatewayState, GatewayStateHandler
from .utils import GatewayLogger
from .utils import GatewayUtilsCrypto
from .proto import gateway_pb2 as pb2

import rados
Expand Down Expand Up @@ -1129,8 +1130,10 @@ def start_service(self):
t.start()

local_state = LocalGatewayState()
dummy_crypto = GatewayUtilsCrypto(None)
gateway_state = GatewayStateHandler(self.config, local_state,
self.omap_state, self._state_notify_update, f"discovery-{socket.gethostname()}")
self.omap_state, self._state_notify_update,
dummy_crypto, f"discovery-{socket.gethostname()}")
gateway_state.start_update()

try:
Expand Down
Loading

0 comments on commit 5e02521

Please sign in to comment.